ReferenceCountedArray Change?


#1

I updated to the tip and I’m getting an error about a ReferenceCountedArray having a private copy constructor.

Did the syntax of copy change, so I can’t copy? I’m trying to make a ReferenceCountedArray instance initialized with a copy of another.

Do I need to write it differently? Xcode doesn’t show me the offending line, but I do have:

const ReferenceCountedArray <BufferUseRecord, CriticalSection>& BufferList::getBufferRecs () { return (buffers); }
defined as:

Used as:

ReferenceCountedArray <BufferUseRecord, CriticalSection> currentBuffers (readyBuffers->getBufferRecs ());

Bruce


#2

Hmm. Thought I was getting quite good at this c++ lark, but there’s always something to learn…

I had changed the copy constructor to take a templated parameter, so that it can be used to copy from arrays of compatible polymorphic types. I assumed that this method would also work perfectly well as the normal copy constructor, but it seems not. I don’t know if it’s because of a compiler idiosyncrasy, or perhaps an obscure footnote in the c++ standard, but for some reason the compiler is refusing to use my templated version in cases where it could use a standard copy constructor.

Anyway, I’ve added a normal copy constructor to the class now, so it should all work!


#3

The official reason is that a template copy constructor can not exist.
What you’ve made is a template constructor that “behave” like a copy constructor.
The standard state that if a copy constructor doesn’t exists, the compiler must provide an implicit one, bypassing any template lookup at the time.


#4

It seems a bit illogical to me… When the compiler needs a copy constructor, I’d have thought that it would just look for a function that fits the requirement, just like it does when you make any other function call. Can’t really see why there’d need to be a special case for a copy constructor, but I’m sure there’s a very obscure and convoluted reason why it has to be done that way!


#5

The reason is in the implicit part. Copy constructor and assignment operator are special case in C++, as they are the only methods that a compiler can write itself.
Usually, the method resolution logic is:

  1. If there is a perfect fit, use it
  2. If a default type conversion can do, to use the perfect fit, use it.
  3. If there is a template version that could match better than any other template one, instantiate it and use it.

For copy constructor, I guess the implicit part comes in between 1 and 2, stating “if 1 or 2 doesn’t do, write my own implicit code and use it”.

If you think about it more deeply, it make sense.
This code:

template<T>
class Any
{
    template <typename U>
    Any(U & u);  // Conversion constructor
};

would be at the same time an “accept-all-types” and a copy constructor (when U = const Any), yet the developper probably doesn’t want this (if he either thought about this).


#6

Yep, that’ll be it.

I guess in c++11 it could be done more neatly by using the “X (const X&) = delete” notation, or even by writing a default constructor that calls the templated constructor. It’s just a bit annoying in c++03 to have to write basically the same function twice.


#7

Thrice ye shall !
Don’t forget the assignment operator!