函数中的临时对象参数生存期

Ric*_*ick 25 c++

我已经阅读了几篇关于临时对象生命周期的帖子.总之,我了解到:

临时在包含它的完整表达式结束后被销毁.

但是这段代码超出了我的预期:

#include <memory> 
#include <iostream> 

void fun(std::shared_ptr<int> sp)
{
    std::cout << "fun: sp.use_count() == " << sp.use_count() << '\n'; 
    //I expect to get 2 not 1
} 

int main()
{
    fun(std::make_shared<int>(5));  

}
Run Code Online (Sandbox Code Playgroud)

所以我认为这里有2个智能指针对象,一个是std::make_shared<int>(5)临时的未命名对象,另一个sp是函数内部的局部变量.所以根据我的理解,临时的不会在完成函数调用之前"死".我希望输出为2而不是1.这里有什么问题?

Bau*_*gen 24

sp如果移动没有被省略,那么前C++ 17 是从临时移动构造的.在任何一种情况下,sp都是资源的唯一所有者,因此使用计数正确地报告为1.这是过载10)此参考中.

虽然临时仍然存在,但如果没有被删除,它处于移动状态并且不再保留任何资源,因此它不会对资源的使用计数产生影响.

从C++ 17开始,由于保证了复制/移动省略,因此不会创建临时文件,并且sp是在适当的位置构建的.


上述参考文献中的确切措辞:

10)移动-构造一个shared_ptrr.构造之后,*this包含前一个状态的副本r,r为空且其存储的指针为空.[...]

在我们的例子,r指的是暂时的,*thissp.


Yak*_*ont 12

有一个奇怪的概念,称为elision.

Elision是一个允许编译器获取两个对象的生命周期并合并它们的过程.通常人们会说复制或移动构造函数"被省略",但真正省略的是两个看似不同的对象的身份.

根据经验,当使用匿名临时对象直接构造另一个对象时,它们的生命周期可以一起消除.所以:

A a = A{}; // A{} is elided with a
void f(A);
f(A{}); // temporary A{} is elided with argument of f
A g();
f(g()); // return value of g is elided with argument of f
Run Code Online (Sandbox Code Playgroud)

在某些情况下,可以使用返回值来省略命名变量,并且可以将两个以上的对象一起省略:

A g() {
  A a;
  return a; // a is elided with return value of g
}
A f() {
  A x = g(); // x is elided with return value of g
             // which is elided with a within g
  return x;  // and is then elided with return value of f
}
A bob = f(); // and then elided with bob.
Run Code Online (Sandbox Code Playgroud)

A上述代码中只存在一个实例; 它只有很多名字.

情况更进一步.在此之前,所讨论的对象必须在逻辑上是可复制的/可移动的,并且简单地消除了elision调用构造函数并共享对象标识.

一些以前被省略的东西(在某种意义上)是"保证省略",这实际上是另一回事."保证省音"基本想法prvalues(东西用来在预临时对象)现在是关于如何创建对象抽象的指令.

在某些情况下,临时实例是从它们实例化的,但在其他情况下,它们仅用于在其他某些地方构建其他对象.

所以在你应该想到这个函数:

A f();
Run Code Online (Sandbox Code Playgroud)

作为返回如何创建的指令A的函数.当你这样做:

A a  = f();
Run Code Online (Sandbox Code Playgroud)

你说"使用f返回构造A命名的指令a".

同样,A{}不再是暂时的,但指示没有如何创建A.如果你把它单独放在一行,那么这些指令用于创建一个临时的,但在大多数情况下,逻辑或实际上不存在暂时的.

template<class T, class...Us>
std::shared_ptr<T> make_shared(Us&&...);
Run Code Online (Sandbox Code Playgroud)

这是一个返回如何创建的指令的函数shared_ptr<T>.

 fun(std::make_shared<int>(5)); 
Run Code Online (Sandbox Code Playgroud)

在这里,您将这些说明应用于fun类型的文件std::shared_ptr<int>.

在没有恶意编译器标志的前[C++ 17]中,elision的结果在这里实际上是相同的.在这种情况下,临时身份与参数合并fun.

在任何实际情况下都会有一个临时shared_ptr引用计数为0; 声称这是错误的其他答案.可能发生这种情况的一种方法是,如果你传入编译器执行elision的标志(上面的恶意编译器标志).

如果你确实传入了这样的标志,则将shared_ptr其移入参数中fun,并且它的引用计数为0.因此use_count将保持为0.