我已经阅读了几篇关于临时对象生命周期的帖子.总之,我了解到:
但是这段代码超出了我的预期:
#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_ptr从r.构造之后,*this包含前一个状态的副本r,r为空且其存储的指针为空.[...]
在我们的例子,r指的是暂时的,*this对sp.
Yak*_*ont 12
c ++有一个奇怪的概念,称为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上述代码中只存在一个实例; 它只有很多名字.
在c ++ 17中,情况更进一步.在此之前,所讨论的对象必须在逻辑上是可复制的/可移动的,并且简单地消除了elision调用构造函数并共享对象标识.
在c ++ 17之后,一些以前被省略的东西(在某种意义上)是"保证省略",这实际上是另一回事."保证省音"基本想法prvalues(东西用来在预临时对象C++ 17)现在是关于如何创建对象抽象的指令.
在某些情况下,临时实例是从它们实例化的,但在其他情况下,它们仅用于在其他某些地方构建其他对象.
所以在c ++ 17中你应该想到这个函数:
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.
| 归档时间: |
|
| 查看次数: |
1733 次 |
| 最近记录: |