I am trying to understand the use of a shared_ptr p
when it is used in the construction of an unnamed shared_ptr
and the effects this has on p
. I was toying with my own examples and wrote the following piece of code:
shared_ptr<int> p(new int(42));
cout << p.use_count() << '\n';
{
cout << p.use_count() << '\n';
shared_ptr<int>(p);
cout << p.use_count() << '\n';
}
cout << p.use_count() << '\n';
Output:
1
1
0
1
p
to create a temp. shared_ptr
(i.e
an unnamed shared_ptr
)?use_count
increased. Is the temp.object destroyed even
before we exit the block at line 7. p
's use count becomes zero inside the block,
how come it is 1 again after we exit the block? If I would have used a named shared_ptr
q
on line 5, i.e:
shared_ptr<int>q(p);
Everything would work as expected, inside the block after line 5 the use count would be 2 and after we exit the block it would be 1 again.
According to the C++ Standard (8.5.1.3 Explicit type conversion (functional notation))
1 A simple-type-specifier (10.1.7.2) or typename-specifier (17.7) followed by a parenthesized optional expressionlist or by a braced-init-list (the initializer) constructs a value of the specified type given the initializer...
So the expression in this expression statement
shared_ptr<int>(p);
looks like an explicit type conversion (functional) expression.
On the other hand, a declarator in a declaration can be enclosed in parentheses. For example
int ( x );
is a valid declaration.
So this statement
shared_ptr<int>(p);
can be interpretated as a declaration like
shared_ptr<int> ( p );
So there is an abiguity.
The C++ Standard resolves this ambiguity the following way (9.8 Ambiguity resolution)
1 There is an ambiguity in the grammar involving expression-statements and declarations: An expression statement with a function-style explicit type conversion (8.5.1.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.
Thus this statement in the inner code block
shared_ptr<int>(p);
is a declaration of a new shared pointer with the name p
that hides the previous declaration of the object with the same name p
in the outer code block and that is created by using the defalut constructor
constexpr shared_ptr() noexcept;
According to the description of this constructor
2 Effects: Constructs an empty shared_ptr object.
3 Postconditions: use_count() == 0 && get() == nullptr.
If you want to deal with an expression instead of the declaration then all you need to do is to enclose the body of the statement in parentheses getting a primary expression in an expression statement.
Here is a demonstrative program.
#include <iostream>
#include <memory>
int main()
{
std::shared_ptr<int> p( new int( 42 ) );
std::cout << "#1: " << p.use_count() << '\n';
{
std::cout << "#2: " << p.use_count() << '\n';
( std::shared_ptr<int>( p ) );
std::cout << "#3: " << p.use_count() << '\n';
}
std::cout << "#4: " << p.use_count() << '\n';
return 0;
}
In this case its output is
#1: 1
#2: 1
#3: 1
#4: 1