From: Peng Yu on
Hi,

I heard that most (if not all) containers in C++ standards (including
the upcoming one) and in boost.org do not follow copy on write
semantics. (Please correct me if I'm wrong.)

Therefore, if I need to construct some container in a function and
return it. I'd better return a shared_ptr of the container rather than
the container itself. For example, should return
boost::shared_ptr<tr1::unordered_map> rather than tr1::unordered_map.

If there is return value optimization (RVO), I think that I can return
tr1::unordered_map as the compile can optimize away unnecessary coping
in certain cases. But I think that there cases where RVO doesn't help.
For example, if tr1::unordered_map is returned from a function that is
only available in the object format (through linkage), the copying can
not be avoided, right?

Therefore, I think that it is always safer to return a shared_ptr
rather the contain. Would you please let me know if my understanding
is correct?

--
Regards,
Peng

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Ulrich Eckhardt on
Peng Yu wrote:
> I heard that most (if not all) containers in C++ standards (including
> the upcoming one) and in boost.org do not follow copy on write
> semantics. (Please correct me if I'm wrong.)

You are correct.

> Therefore, if I need to construct some container in a function and
> return it. I'd better return a shared_ptr of the container rather than
> the container itself.

Actually, I wouldn't say so. I would rather use a std::auto_ptr, as
ownership transfer is exactly what I want to express. This saves the
overhead of atomic increment/decrement operations for the reference counter
and the allocation of the reference counter, both of which are not
completely negligible.

The only drawback left is that I would like to express via the returned type
that the function will not return a null pointer, but neither std::auto_ptr
nor boost::shared_ptr support anything like that.

> If there is return value optimization (RVO), I think that I can return
> tr1::unordered_map as the compile can optimize away unnecessary coping
> in certain cases. But I think that there cases where RVO doesn't help.
> For example, if tr1::unordered_map is returned from a function that is
> only available in the object format (through linkage), the copying can
> not be avoided, right?

This has two sides, both of which are implementation-defined, so no
guarantees are possible. The first side is the inside of the function. It
can create the local map in the same place where it would construct the
returnvalue, thus saving one copy. The second side is the calling function,
which can use the object in the place where it is created by the called
function instead of creating a local and copying it there, which saves
another copy. Both parts are possible even if the two are compiled
completely separated from each other.


Note: You mentioned copy on write (COW). There is a very simple way to get
that, and that is to use std::auto_ptr<T> and boost::shared_ptr<T const>.
If you exclusively own the object (auto_ptr) you may modify it as you want.
If you have shared ownership (shared_ptr) you may not modify it but instead
have to copy it first. If you assign an auto_ptr to a shared_ptr, the
auto_ptr becomes null and the shared_ptr assumes ownership, which can then
be shared. This doesn't do the COW automatically behind the scenes, but is
very handy if you share large objects that only occasionally need copying.

Uli

--
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Daniel Krügler on
On 15 Jun., 21:59, Jeff Flinn <TriumphSprint2...(a)hotmail.com> wrote:
> Goran wrote:
[..]
> > I think so, too, but you have swap method, which is efficient. So:
>
> > LibMapType map;
> > map.swap(LibFuncReturningMap(...));
>
> IIRC, that won't compile on gcc 4.0.1 for me(but does with MSVC's
> extensions). I need to:
>
> > LibMapType map;
> > LibFuncReturningMap(...).swap(map);

Yeah, this is the only correct way, because swap requires a
(mutable) lvalue, but above an rvalue was provided. It is a
shame, that accepting rvalues at these locations still belong
to the default settings of MSVC...

Greetings from Bremen,

Daniel Kr�gler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Bo Persson on
{ note to moderators redacted. -mod }

Daniel Kr�gler wrote:
> On 15 Jun., 21:59, Jeff Flinn <TriumphSprint2...(a)hotmail.com> wrote:
>> Goran wrote:
> [..]
>>> I think so, too, but you have swap method, which is efficient. So:
>>
>>> LibMapType map;
>>> map.swap(LibFuncReturningMap(...));
>>
>> IIRC, that won't compile on gcc 4.0.1 for me(but does with MSVC's
>> extensions). I need to:
>>
>>> LibMapType map;
>>> LibFuncReturningMap(...).swap(map);
>
> Yeah, this is the only correct way, because swap requires a
> (mutable) lvalue, but above an rvalue was provided. It is a
> shame, that accepting rvalues at these locations still belong
> to the default settings of MSVC...
>

Who runs compilers with default settings? :-) Those are permissive
enough to minimize the number of support cases for the product. A
business optimization.

If we compile with the proper setting - highest warning level - the
compiler will tell us that "the type conversion is not allowed by the
C++ standard".

http://msdn.microsoft.com/en-us/library/186yxbac%28VS.80%29.aspx


Bo Persson



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]