我试图了解在将shared_ptr p
用于未命名shared_ptr
的构造中的用法及其对p
的影响。我正在玩自己的示例,并编写了以下代码:
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
创建临时表是否正确。 shared_ptr
(即
一个未命名的shared_ptr
)?use_count
没有增加。临时对象是否被破坏?
在我们从第7行退出该块之前。p
的使用计数在块内变为零,
退出街区后又怎么又是1? 如果我在第5行使用了命名为shared_ptr
q
的话,即
shared_ptr<int>q(p);
一切都会按预期进行,在第5行 使用计数将为2,而在退出该块之后,它将再次为1。
答案 0 :(得分:3)
根据C ++标准(8.5.1.3显式类型转换(功能表示法))
1一个简单类型说明符(10.1.7.2)或类型名称说明符(17.7) 后面加上括号的可选表达式列表或 braced-init-list(初始化程序)构造一个指定值 输入给定的初始值...
因此该表达式语句中的表达式
shared_ptr<int>(p);
看起来像一个显式的类型转换(函数)表达式。
另一方面,声明中的声明符可以放在括号中。例如
int ( x );
是有效的声明。
所以这句话
shared_ptr<int>(p);
可以解释为声明,例如
shared_ptr<int> ( p );
因此存在歧义。
C ++标准通过以下方式(9.8歧义分辨率)解决了这种歧义
1涉及表达陈述的语法有歧义 和声明:具有函数样式的表达式语句 显式类型转换(8.5.1.3),因为其最左边的子表达式可以 与第一个声明者的声明没有区别 以(。在这种情况下,该语句为声明。
因此该语句在内部代码块中
shared_ptr<int>(p);
是名称为p
的新共享指针的声明,该声明隐藏了外部代码块中同名p
的对象的先前声明,并且是使用defalut构造函数创建的
constexpr shared_ptr() noexcept;
根据此构造函数的说明
2效果:构造一个空的shared_ptr对象。
3个后置条件: use_count()== 0 && get()== nullptr。
如果要处理表达式而不是声明,则只需将语句的主体括在括号中即可在表达式语句中获取主表达式。
这是一个演示程序。
#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;
}
在这种情况下,其输出为
#1: 1
#2: 1
#3: 1
#4: 1
答案 1 :(得分:2)
在第5行中,创建新变量p。空一个。看到这个:
shared_ptr<int> p(new int(42));
cout << p.use_count() << '\n';
cout << "address " << &p << "\n";
{
cout << p.use_count() << '\n';
shared_ptr<int>(p);
cout << "address " << &p << "\n";
cout << p.use_count() << '\n';
}
cout << p.use_count() << '\n';
输出:
1
address 0x7ffcf3841860
1
address 0x7ffcf3841870
0
1
请注意,p的地址已更改。
要解决此问题,请更改括号:
shared_ptr<int> {p};
答案 2 :(得分:1)
shared_ptr<int>(p);
等效于shared_ptr<int> p;
,实际上是在该块内创建另一个p
,以隐藏前一个p
。此处的括号不是构造函数调用,而是由编译器解释的,就像将表达式分组的数学括号一样,该表达式是新构造的shared_ptr的名称。
shared_ptr<int>q(p);
会创建一个名为q
的新shared_ptr,以引用p
作为参数调用构造函数(从而增加引用计数)。在这种情况下,括号被解释为包含构造函数参数。
请注意,当使用大括号{}
时,std::shared_ptr<int>q{p};
将继续给出预期的结果(1 1 2 1),而std::shared_ptr<int>{p};
将显示(1 1 1 1),因为编译器现在考虑围绕它的小块的第二p
部分。用C ++进行编程的乐趣。