0

I have developed two classes Ptr and Cntr as part of the Accelerated C++ Ch.14-6 exercise.

  • The Ptr class is a handle class that contains a pointer member and allows the user to control whether or not to copy the underlying object referenced by the pointer.
  • The Cntr class is a class containing a member of size_t type which is the count of pointers pointing to a given object.

I receive an error when Ptr attempts to call some (not all) Cntr constructors and the Cntr destructor:

error: no match for call to '(Cntr) (std::size_t*)'

error: no match for call to '(Cntr) ()'

I have solved some issues by moving constructors into initialization lists in Ptr. However, in other cases I need to call the ~Cntr() destructor outside an initialization list. Guidance as to why this works it works in an initialization list but not outside would help also.

This code sample is not small but within limits of other code I've seen on stackoverflow.com. My complete ptr.h header file is listed as follows:

#ifndef GUARD_Ptr
#define GUARD_Ptr

//Ptr.h header file
#include "vec.h"

using std::size_t;

template <class T> T* clone (const T* tp);
template<> Vec<char>* clone(const Vec<char>* vp);
template <class T> class Ptr;

class Cntr {
public:
    size_t* refptr; // member made public while debugging

    Cntr() : refptr(new size_t(1)) { }
    Cntr(const Cntr& cntptr) : refptr(cntptr.refptr) { ++*refptr; }
    Cntr(size_t* t) : refptr(t) { }

    ~Cntr()
    {
        delete refptr;
    }

    size_t value() {
        return *refptr;
    }

    size_t add() {
        ++*refptr;
        return *refptr;
    }

    size_t subtract() {
        --*refptr;
        return *refptr;
    }   

};


template <class T>
class Ptr {
public:
    // new member to copy the object conditionally when needed
    void make_unique()
    {
       if (cntptr.value() != 1) {
            cntptr.subtract();
            cntptr(new size_t(1));
            p = p? clone(p) : 0; // call the global version of close
       }
    }

    // the rest of the class looks like Ref_handle except for its name
    Ptr() : p(0), cntptr()  { }
    Ptr(T* t): p(t), cntptr() { }
    Ptr(const Ptr<T>& h): p(h.p), cntptr(h.cntptr) { }

    Ptr<T>& operator=(const Ptr<T>& rhs)
    {
        cntptr.add();
        // free the lhs, destroying pointers if appropriate
        if (cntptr.subtract() == 0) {
            ~cntptr();
            delete p;
        }
        // copy in values from the rhs
        cntptr(rhs.cntptr);
        p = rhs.p;
        return *this;
    }

    ~Ptr()
    {
        if (cntptr.subtract() == 0) {
            ~cntptr();
            delete p;
        }
    }

    operator bool() const { return p; }
    T& operator*() const {
        if (p)
            return *p;
        throw std::runtime_error("unbound Ptr");
    }

    T* operator->() const {
        if (p)
            return p;
        throw std::runtime_error("unbound Ptr");
    }

private:
    T* p;
    Cntr cntptr;
};


#endif //GUARD_Ptr
yellowjacket05
  • 149
  • 1
  • 2
  • 12
  • I found another question with the same error, but the resolution does not answer this problem: http://stackoverflow.com/questions/17818282/no-matching-functions-for-call-to-constructor-c – yellowjacket05 Jan 20 '15 at 03:21
  • You should not call destructors directly in this program at all (and the syntax of calling destrucrors is totally different). – n. m. could be an AI Jan 20 '15 at 03:39
  • I was able to compile calling delete cntptr.refptr. This seems less elegant than being able to delete the cntptr object and allow the cntptr destructor to handle the deletion. I still have an error with the constructor which is defined to use a size_t. – yellowjacket05 Jan 20 '15 at 03:49
  • Once again, explicitly calling a destructor doesn't do what you want and you shouldn't do it. You only call a destructor if you use *placement new* in your program. – n. m. could be an AI Jan 20 '15 at 03:53
  • If you want elegance, you need to call `subtract` from the destructor of Cntr, rather than from the destructor of Ptr. Furthermore, as you need to delete the refcount only after `subtract` makes it zero, it is logical to move the entire operation `if (*refptr != 0) delete refptr;` into `subtract`. – n. m. could be an AI Jan 20 '15 at 04:06

1 Answers1

1

Your header file is compiled without any problem. It seems that there is problem with template instantiation of the code. Please make ensure that the class T which is being hold by Ptr should conform to the template. Check if the copy constructor is private or public?

See my sample run at http://codepad.org/m7aSJ9pa.

doptimusprime
  • 9,115
  • 6
  • 52
  • 90
  • I tested your suggestion by commenting all code in my main block, no template instantiation occurs, but I still receive this error. The main unresolved issue is the Cntr(new size_t(1)) constructor. This constructor is not affected by the class T chosen. I think the error lies in the g++ compiler/linker with my version of Code::Blocks. – yellowjacket05 Jan 20 '15 at 03:51
  • Then try to assign instead of using initializer list. – doptimusprime Jan 20 '15 at 03:58
  • Since the code works in codepad, I have concluded this is a g++ compiler issue. Others have had quirky issues and seems less robust than the Visual Studio C++ compiler. – yellowjacket05 Jan 21 '15 at 02:43