Upa*_*yan -2 vector reference-counting shared-ptr c++11
use_count()使用iteratorde-reference 打印共享指针时,下面的程序输出意外值std::vector:
#include<iostream>
#include<memory>
#include<vector>
class A;
typedef std::shared_ptr<A> sharedPtr;
typedef std::vector<sharedPtr> sharedPtrVect;
typedef sharedPtrVect::const_iterator vectItr;
class A
{
public:
A(int inp): m_Val(inp) { /*std::cout << "*** A ctor called: " << m_Val << " ***" <<std::endl;*/ }
~A() { /*std::cout << "### A dtor called: " << m_Val << " ###" <<std::endl; */}
int getVal() const { return m_Val; }
private:
int m_Val;
};
int main()
{
sharedPtrVect myVect1, myVect2;
vectItr myVectItr;
std::shared_ptr<A> tmpPtr;
for(int i = 1 ; i <= 5 ; i++ ) {
std::cout << "Pushed back: " << i << std::endl;
tmpPtr = std::make_shared<A>(i);
myVect1.push_back(tmpPtr);
}
myVectItr = myVect1.begin();
for( ; myVectItr != myVect1.end() ; ++myVectItr) {
std::cout << "-----------------------------" << std::endl;
std::cout << "Element number: " << (*myVectItr).get()->getVal() << std::endl;
std::cout << "Element use count: " << (*myVectItr).use_count() << std::endl;
std::cout << "-----------------------------" << std::endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面代码的输出是:
Pushed back: 1
Pushed back: 2
Pushed back: 3
Pushed back: 4
Pushed back: 5
-----------------------------
Element number: 1
Element use count: 1
-----------------------------
-----------------------------
Element number: 2
Element use count: 1
-----------------------------
-----------------------------
Element number: 3
Element use count: 1
-----------------------------
-----------------------------
Element number: 4
Element use count: 1
-----------------------------
-----------------------------
Element number: 5
Element use count: 2 //I am not sure why or how this is 2?
-----------------------------
Run Code Online (Sandbox Code Playgroud)
我不明白use_count()最后一个向量元素是如何2.不应该像其他人一样吗?我没有创建存储在向量的最后一个元素中的共享指针的任何副本.我在这里错过了什么?
编辑:我在C++ 98方面有很好的经验,但在C++ 11方面经验较少.
不应该像其他人一样吗?我没有创建存储在向量的最后一个元素中的共享指针的任何副本.我在这里错过了什么?
但是你正在创建一个副本.你push_back()来自tmpPtr.push_back()将其参数的副本放入向量中,除非您告诉它移动.(稍后会详细介绍!)
因此,除了最后一个元素之外发生的事情是:
tmpPtr 拥有对共享资源的唯一引用push_back()是一个副本,所以复制构造函数shared_ptr将使用次数增加到2tmpPtr,释放对前一个元素的资源的引用,从而减少其使用计数.但是,当然,在循环的最后一次迭代中没有后续赋值.因此,在打印时,tmpPtr仍然在范围内,并且它保留对分配的最后一个资源的引用.因此,最后一个元素的引用次数增加了1.这对我来说似乎是完全可取的.;)
要查看您期望的结果,您需要tmpPtr在复制之后但在打印之前销毁,或者首先从它中删除副本.for正如SirGuy 在评论中指出的那样,前者可以通过将其声明移入循环来完成.
然而,显然,后者是优越的.我们怎么做?那么,C++ 11让我们动来代替.所以,你可以emplace_back( std::move(tmpPtr) )在其中move将转换为一个右值,因此调用的布展构造vector元素.这将导致tmpPtr在被移入时释放其引用vector,有效地确保使用计数始终为1.这使得tmpPtr(像任何移动的对象一样)处于有效但未指定的状态,即仅用于重新分配.
(注意:push_back()将实现相同的目的,但我通常更喜欢emplace_back()在任何可能的情况下使用,因为它在其他情况下更有效,所以它是一个更好的默认值.)
当然,您可以将这两者结合起来:tmpPtr在for循环范围内声明,然后从中移动.但是 ......你根本不需要tmpPtr!它似乎没有任何用处.所以,你可以不使用它,而是直接使用它emplace_back()的结果make_shared().因为它的返回值将是一个rvalue,它将隐含地移入vector; 不需要施放std::move.