与临时对象一起使用时了解C ++ std :: shared_ptr

时间:2019-06-18 15:04:53

标签: c++ syntax expression shared-ptr declaration

我试图了解在将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
  1. 第5行使用p创建临时表是否正确。 shared_ptr(即 一个未命名的shared_ptr)?
  2. 如果是,为什么use_count没有增加。临时对象是否被破坏? 在我们从第7行退出该块之前。
  3. 如果它被销毁并且p的使用计数在块内变为零, 退出街区后又怎么又是1?

如果我在第5行使用了命名为shared_ptr q的话,即

shared_ptr<int>q(p);

一切都会按预期进行,在第5行 使用计数将为2,而在退出该块之后,它将再次为1。

3 个答案:

答案 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 ++进行编程的乐趣。