Re: initializing / assigning nullptr to shared_ptr vs. unique_ptr
Am 22.11.2014 um 16:04 schrieb firespot71:
Dear all,
What is the officially defined behaviour for initializing a
std::shared_ptr with a nullptr argument or assigning a nullptr to an
existing shared_ptr?
Since C++11 initializing a shared_ptr with a nullptr argument will
resolve to
constexpr shared_ptr(nullptr_t) : shared_ptr() { }
so it has the same semantics as default-initializing a shared_ptr
object, that is, the created object shall be empty and use_count() == 0.
Now when assigning a shared_ptr with a nullptr argument the wording
seems IMO clear that this is equivalent to constructing a shared_ptr
from nullptr (see above) and assigning this rvalue to the assigned-to
object effectively using
shared_ptr& operator=(shared_ptr&& r) noexcept;
Now this operator is specified as follows:
Effects: Equivalent to shared_ptr(std::move(r)).swap(*this).
Now the move-constructor of shared_ptr has:
Postconditions: *this shall contain the old value of r. r shall be
empty. r.get() == 0.
So the temporary shared_ptr has the same use_count (0) as it's argument
and the swap operation just transfers this state into the assigned-to
object. So again, we have a required use_count of 0 again.
Including how does behaviour differ compared to a
std::unique_ptr?
Using N3690 as reference (I know its a draft only but I suppose fairly
close to the official version) then in 20.9.1.2.3 it says that assigning
an object of type nullptr_t to a unique_ptr is the same effect as reset.
The class template's summary (begin of 20.9.1.2) lists a constexptr
constructor taking nullptr_t as overload, behaving like a default
constructor. In short it appears these operations are equivalent.
Unless we need to discuss details of "equivalent", I agree so far.
For shared_ptr the issue is the same with the constructor, but I cannot
locate an operator= overload (so am I correct that when nullptr becomes
assigned to a shared_ptr it goes through an implicit conversion
constructing a temporary shared_ptr from the nullptr?).
I agree with your interpretation (see above).
The surprise came when I ran the following little test program (MS
Visual Studio 2012 Express, update 4):
[..]
in both part 1 and part 2 the use_count is 1 for a1 and a2, and 0 for
a3. In part 3 the use_count is 0 for all three.
Obviously here the constructor taking nullptr does not yield the same
state as the default constructor. Similarly, assinging nullptr does not
yield the same state as reset.
Clearly use_count is not that much of use practically speaking, but
still it appears as observable behaviour to me.
Is the output correct according to the standard, do I mess up here
something or is MS VS 2012 on the wrong side here?
The library implementation of VS 2012 must be incorrect, because its
observable behaviour differs from what the standard requires.
HTH & 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! ]