views:

168

answers:

3

I am having a problem placing an instance of my reference-counting Pointer<Type> class into my Array class. Using the debugger, it seems that the constructor is never called (which messes up the reference-count and causes a segfault down the line)!

My push_back function is:

void push_back(const T& element)
{
 if (length >= max)
  reallocate(max > 0 ? max * 2 : 1);

 new (&data[length]) T(element);
 ++length;
}

The reference-count is the same before new is called as after. I'm very sure this is the problem, but I can't figure out why the constructor wouldn't be called. Additionally Pointer::Pointer(...) compiles whether it takes a Pointer<T>& or a const Pointer<T>& (huh?), and has the problem regardless as well!

Maybe there are some details on placement new I am not taking into account. If anyone has some thoughts, they'd be much appreciated!

edit: [as requested, a relevant excerpt from Pointer]

// ...
private:
    T* p;

public:
    //! Constructor
    Pointer()
        : p(0)
    {

    }

    //! Copy Constructor
    template<class X> Pointer(Pointer<X>& other)
        : p(other.getPointer())
    {
        if (p)
            p->incrementRef();
    }

    //! Constructor (sets and increments p)
    Pointer(T* p)
        : p(p)
    {
        if (p)
            p->incrementRef();
    }

    //! Destructor (decrements p)
    ~Pointer()
    {
        if (p)
            p->decrementRef();
    }
// ...

I've also implemented operator = for Pointer<T>& and T*, as well as operator -> and operator T*

+2  A: 

According to docs constructor should be called... Few things you can check:

To test pointer:

Pointer<int> p1(new int);
Pointer<int> p2(p1); // Does this call constructor properly?

To test array:

Array<std::string> array;
std::string str("bla");
array.push_back(str); // Does this call string's constructor

That's what fails, right?

Array<Pointer<int> > array;
Pointer<int> p1(new int);
array.push_back(p1);

If all else fails, you can always do this to surely invoke copy constructor or operator=

T* t = new (&data[length]) T();
*t = element;
Eugene
And hopefully your Pointer<T> doesn't define implicit conversion to T*...
Eugene
@Eugene: Ah. It does! Is that a problem? That seemed like a useful addition...
@Eugene: The same problem occurs with operator T*() removed, but i'm still curious what the problem would be with implementing that...
@Eugene: I went through your tests for Pointer and Array and both worked fine. When I tried an Array of Strings, it entered my String's copy constructor (Pointer's is posted in my edit above) : //! Copy Constructor String(const String<T> }
Implicit conversion might easily end up bypassing your reference counter (there is a reason boost smart pointers don't implement it).
Eugene
Actually you are using deep reference counting, so it is not as bad.
Eugene
A: 

Please post your Pointer class here. I would think that the T in this class is Pointer ? If so is the code supposed to do: new (&data[length]) Pointer(element);

which I'm having a hard time understanding..

why not just do: data[length] = element; I'm assuming data[length] is Pointer

problem_solver
+2  A: 

Your comment and your code are out of sync:

//! Copy Constructor
template<class X> Pointer(Pointer<X>& other)

A constructor generated from a class template is not a copy constructor (there's a footnote in 12.8 [class.copy] that clarifies this), so won't prevent the compiler from generating a copy constructor for you. This generated constructor will be a better match for a standard copy as non-template functions are preferred to template functions in overload resolution.

It appears that you need to write an explicit copy constructor in your pointer class to get the desired effect.

Charles Bailey
@Bailey, ah! This is likely the problem! I need a function that takes a Pointer<A> to be able to take a Pointer<B> if B inherits from A though! How can I accomplish this at the same time? Writing both templated and non-templated versions of this function is ambiguous for the compiler...
It shouldn't be ambiguous. Have you tried it? Either the copy constructor is a match, in which case it beats the template constructor for the reasons I mentioned above, or it isn't a match, in which case the template constructor should pick up the other valid cases.
Charles Bailey
@Bailey: Thanks! That was the solution. I could have sworn I tried it before and got an error regarding some ambiguity...