Re: Copy constructor not being called on function return

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



John Love-Jensen wrote:
It looks like it optimises the temporary out.

That is correct, even in non-optimized code, the compiler can (and should)
"optimize the temporary out".

I would have expected to see a constructor followed by a copy constructor, and
then 2 destructors.

Except for "named return value optimization" (NRVO), which means the
compiler can avoiding doing that in several circumstances.

You should not rely on side-effects in your copy constructor.

Is there any way to force the copy constructor to be called in the assignment
of myfoo to getFoo()?

Yes, you can make an explicit method which does copy construction, and call
that instead of using the standard copy constructor.

I have a case where it is vital that the copy constructor is run in this
instance as the the temporary (f) references data which goes out of scope in
getFoo() and so myfoo has references to already released memory - the copy
constructor deals with this elegantly.

In that case, you may want to make sure that you use std::swap semantics to
change ownership, or use an explicit method rather than the copy-constructor
to handle this situation.

I recommend Herb Sutter's books Exceptional C++, More Exceptional C++, C++
Coding Style, and Exceptional C++ Style.  (Hmmm, I guess I'm just a Herb
Sutter fanboy.)

Thanks for the answer, I'd thought that was probably the case but hadn't been able to track down anything definitive. I have 2 of those books but maybe missed that section :) My actual problem involves a smart pointer which can refer to a const block while it is in scope (I have control of that) but on a copy will shift to using a shared pointer (does this deep-copy constitute side-effects of a copy constructor?). Something like:

class SmartPtr
{
public:
 // ...
SmartPtr(const SmartPtr& copy) { /* creates shared_ptr to copy into if necessary */ }

 void setConst(const void*,unsigned sz);

private:
 void* const_ptr;
unsigned size;
 SharedPtr shared_ptr; // may or may not be set
};


SmartPtr someFunc()
{
 char some_data[100];
 SmartPtr smart_ptr;
 smart_ptr.setConst(some_data,sizeof(some_data));

 return smart_ptr;
}

This is a contrived example but it does have real application. The problem (and I know this won't change anything) with NRVO is that 'some_data' goes out of scope at the same time as 'smart_ptr', but smart_ptr actually persists as a result of NRVO.

The code below should do the trick but I am using a range of compilers (from gcc 2.95-4.x, as well as Borland) and I'm not sure all of them support NRVO. This will be a performance issue because those without NRVO will end up with a double copy.

SmartPtr SmartPtr::copy() const { return *this; }

SmartPtr someFunc()
{
 char some_data[100];
 SmartPtr smart_ptr;
 smart_ptr.setConst(some_data,sizeof(some_data));

 return smart_ptr.copy();
}

The only solution I can think of to solve this involves macros which I tend to avoid:

#ifdef HAS_NRVO
 #define CREATE_COPY(sp) sp.copy()
#else
 #define CREATE_COPY(sp) sp
#endif

SmartPtr someFunc()
{
 char some_data[100];
 SmartPtr smart_ptr;
 smart_ptr.setConst(some_data,sizeof(some_data));

 return CREATE_COPY(smart_ptr);
}

Can anyone think of a more elegant way of managing this, and is there a way of determining at compile-time whether a compiler supports NRVO?

Thanks for the help so far,
Regards


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux