ScopedPointer, initialisation list and copy constructor?


#1

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:


#2

(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.


#3

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 ?


#4

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).


#5

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


#6

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.


#7

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:


#8

[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!