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

Soh*_*hof 4 c++ syntax expression declaration shared-ptr

我试图了解 ashared_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
Run Code Online (Sandbox Code Playgroud)
  1. p第 5 行用于创建临时变量是否正确。shared_ptr(即未命名的shared_ptr)?
  2. 如果是的话为什么不use_count增加。在我们退出第 7 行的块之前,temp.object 是否已被销毁。
  3. 如果它被破坏了,p块内的使用计数变为零,为什么退出块后它又变成1了?

shared_ptr q如果我在第 5 行使用命名,即:

shared_ptr<int>q(p);
Run Code Online (Sandbox Code Playgroud)

一切都会按预期工作,在第 5 行之后的块内,使用计数将为 2,在我们退出该块后,它将再次为 1。

Vla*_*cow 5

根据 C++ 标准(8.5.1.3 显式类型转换(函数表示法))

1 简单类型说明符 (10.1.7.2) 或类型名称说明符 (17.7) 后跟带括号的可选表达式列表或大括号初始化列表(初始化程序),在给定初始化程序的情况下构造指定类型的值...

所以这个表达式语句中的表达式

shared_ptr<int>(p);
Run Code Online (Sandbox Code Playgroud)

看起来像一个显式类型转换(函数)表达式。

另一方面,声明中的声明符可以用括号括起来。例如

int ( x );
Run Code Online (Sandbox Code Playgroud)

是一个有效的声明。

所以这个声明

shared_ptr<int>(p);
Run Code Online (Sandbox Code Playgroud)

可以被解释为像这样的声明

shared_ptr<int> ( p );
Run Code Online (Sandbox Code Playgroud)

所以存在一个歧义。

C++ 标准通过以下方式解决了这种歧义(9.8 歧义解决)

1 涉及表达式语句和声明的语法存在歧义:以函数样式显式类型转换 (8.5.1.3) 作为其最左侧子表达式的表达式语句与第一个声明符以 ( 开头的声明无法区分。在这些情况下,声明就是声明

因此内部代码块中的这条语句

shared_ptr<int>(p);
Run Code Online (Sandbox Code Playgroud)

是一个新共享指针的声明,其名称p隐藏了外部代码块中同名对象的先前声明p,并且是使用默认构造函数创建的

constexpr shared_ptr() noexcept;
Run Code Online (Sandbox Code Playgroud)

根据这个构造函数的描述

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;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它的输出是

#1: 1
#2: 1
#3: 1
#4: 1
Run Code Online (Sandbox Code Playgroud)