ScopedPointer, initialisation list and copy constructor?

Hi there !

My program exhibits a really strange behaviour !

I got this code

Track::Track( int /*numIns*/, int /*numOuts*/, double /*sampleRate*/, int /*blockSize*/, sb::controller::TimeFactory& timeFactory ) : _timeFactory(timeFactory), _playbackMode(ARRANGEMENT), _currentTime(timeFactory.createTimeFromSamplesNumber(0))

_curentTime type is juce::ScopedPointersb::core::time .

and that’s how timeFactory.createTimeFromSamplesNumber is defined :

juce::ScopedPointer<sb::core::Time> sb::controller::TimeFactory::createTimeFromSamplesNumber( sb::core::SamplesNumber iSamplesNumber ) { juce::ScopedPointer<sb::core::Time> newTime(new sb::core::Time(_synchronizer)); newTime->setSampleTime(iSamplesNumber); return newTime; }

Here, we have only ScopedPointers in action right ?

Now when _currentTime is initialised, I expect that

will be called, to my surprise, it’s not the case !!!

Instead, by tracing through the program, those methods of ScopedPointer are called :

 inline operator ObjectType*() const throw()                                     { return object; }

then

inline ScopedPointer (ObjectType* const objectToTakePossessionOf) throw() : object (objectToTakePossessionOf) { }
Which causes double deletion of the object wrapped by the ScopedPointer.

Of course, I can easily solve the problem by replacing

by

but I would really like to understand why the copy constructor isn’t called. If someone could shed light on this …

EDIT : I’m fully aware that this is probably something I overlooked in C++ rather than a Juce problem. However, as there are some people here who know the inner workings of juce::ScopedPointer they might understand the problem and point me to the right track more efficently than, say, StackOverflow people …:slight_smile:

(First: never use a leading underscore in your variable names!! That’s a convention that’s reserved for the std library - it’s very bad form to use it in your own code. Looks nasty too, IMHO).

Now… the answer to the ScopedPointer question is really very complicated and deep c++… But in summary, a scoped pointer class can either provide an implicit cast to the object pointer (that’s how mine works), or not (that’s how std::auto_ptr works). If you do provide that cast, then it makes it easier to use the pointer object, but it means that there are situations where the compiler can mess-up by adding an implicit cast when you don’t want one. To avoid errors like you’re getting, I added a private constructor that will cause a compile error when such a situation arises… but that only works in GCC. So I presume you’re using MSVC, otherwise your code wouldn’t have compiled at all!

Your alternatives would be to just return a raw pointer (which is how I normally handle this kind of thing, assuming that the caller will decide whether or not it wants to store the object in a ScopedPointer, or some other kind of wrapper). Or you could just use a std::auto_ptr instead, which will work fine, but you’ll need to call get() whenever you want to get the pointer out of it.

Yeah I know it looks ugly but we started like that and now the amount of code which would need to be changed is huge …
Besides, we use it only for private member variables and that’s fine, according to the standard

[quote]17.4.3.2.1 Global names [lib.global.names]
Each name that contains a double underscore (_ _) or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use.
[/quote]

Our private membersstart with underscore + lowercase letter

[quote=“jules”]Now… the answer to the ScopedPointer question is really very complicated and deep c++… But in summary, a scoped pointer class can either provide an implicit cast to the object pointer (that’s how mine works), or not (that’s how std::auto_ptr works). If you do provide that cast, then it makes it easier to use the pointer object, but it means that there are situations where the compiler can mess-up by adding an implicit cast when you don’t want one. To avoid errors like you’re getting, I added a private constructor that will cause a compile error when such a situation arises… but that only works in GCC. So I presume you’re using MSVC, otherwise your code wouldn’t have compiled at all!

Your alternatives would be to just return a raw pointer (which is how I normally handle this kind of thing, assuming that the caller will decide whether or not it wants to store the object in a ScopedPointer, or some other kind of wrapper). Or you could just use a std::auto_ptr instead, which will work fine, but you’ll need to call get() whenever you want to get the pointer out of it.[/quote]

Yes, I’m using MSVC. Thanks for the advice. I’ll probably keep using ScopedPointers allong with release. You’re probably going to add a private constructor in the MSVC version as well, I suppose ?

No, the MSVC compiler can’t cope with two constructors that differ only by the const-ness of their parameter. (Actually this might be fixed in VC2010, I’ve not checked it).

I see ! But then in which case ScopedPointer (ScopedPointer& objectToTransferFrom) can be called ? (the one without const)

Yes, that can be called, of course. Your problem arises from the fact that for some complicated reason the compiler chooses not to call it, and instead casts it to a pointer and then constructs the new object from that.

Yep, I think I got that. I was wondering, just out of curiosity, what is that complicated reason, if you know it of course :slight_smile:
It’s just so I can be a little bit less stupid before going to bed :wink:

[quote]I was wondering, just out of curiosity, what is that complicated reason, if you know it of course
It’s just so I can be a little bit less stupid before going to bed [/quote]

I’m not 100% sure, and it’d probably require some research in the C++ ISO standards document to get a definite answer, but I suspect that the compiler must first try to find a combination of casts/constructors that treats the RHS as const, before giving up and using the constructor that takes a non-const.

No need to describe yourself as stupid about it - this is deep, obscure c++ stuff!