我正在尝试编写Manager class
来管理Test Class
的多个实例。我应该可以通过调用Test Class
来销毁mng.drop(shared pointer to the instance to be dropped)
的实例。
我不应该使用unique_ptr
如何使用shared_ptr
#include <iostream>
#include <iomanip>
#include <memory>
#include <set>
#define DEBUG ON
#ifdef DEBUG
#define DEBUG_MSG(str) do {std::cout << std::setw(75) << std::left << __FUNCTION__ \
<< std::setw(3) << std::left << ":" << std::setw(5) << std::left << __LINE__ \
<< std::setw(5) << std::left << ":"\
<< std::left << str \
<< std::endl;} while( false )
#else
#define DEBUG_MSG(str) do { } while ( false )
#endif
class Test{
public:
Test(int i) : i_(i){
DEBUG_MSG("Constructor");
}
~Test(){
DEBUG_MSG("Destructor");
}
int getI() { return i_; }
void setI(int i){ i_ = i; }
void fn()
{
DEBUG_MSG("Do Something Here");
}
private:
int i_;
};
using sharedPtr = std::shared_ptr < Test >;
class Manager{
public:
sharedPtr createTest(int i)
{
auto ptr = std::make_shared<Test>(i);
list_.insert(ptr);
return ptr;
}
void drop(sharedPtr ptr)
{
list_.erase(ptr);
}
private:
std::set<sharedPtr> list_;
};
int main()
{
Manager mng;
auto test = mng.createTest(50);
DEBUG_MSG("test : " << test.use_count());
test->fn();
mng.drop(test);
DEBUG_MSG("test : " << test.use_count());
system("Pause");
return 0;
}
可以看出:在我的代码中,当我调用mng.drop(test)
- 仍然是the reference count is 1
时,因此对象不会被破坏。
Test::Test : 22 : Constructor
main : 62 : test : 2
Test::fn : 31 : Do Something Here
main : 65 : test : 1
Press any key to continue . . .
修改
My requirement: Manager Class should hold shared_ptr to all Test instances active; It should able to create and destroy Test instance
答案 0 :(得分:3)
由createTest
返回并存储在test
中的指针与管理员管理的所有权共享;在两个对象都被删除之前,它不会被销毁。
createTest
如果客户端应该访问对象而不共享所有权,则应返回weak_ptr
。他们可以暂时锁定指针,以防止在需要访问时删除;虽然你必须相信他们不要永久锁定它,但如果经理因某种原因拥有这种“独特”的所有权真的很重要。
答案 1 :(得分:3)
您的要求没有意义。如果你需要直接控制对象&#39;生命周期,不要使用为间接控制明确设计的智能指针(std::shared_ptr
)。无论如何,为什么你有这样的技术要求?尝试重新协商他们。
如果这不是一个选项,并且您愿意编写符合(不合逻辑)要求的代码,无论后果如何,您都可以这样做:
class Manager{
public:
sharedPtr createTest(int i)
{
std::unique_ptr<Test> ptr(new Test(i));
sharedPtr res(ptr.get(), [](Test*) {});
list_.insert(std::move(ptr));
return res;
}
void drop(sharedPtr ptr)
{
list_.erase(ptr.get()); // This requires C++14, or adapt list_ so that you can search by raw pointer in it
}
private:
std::set<std::unique_ptr<Test>> list_;
};
代码为共享指针提供no-op删除器。对象的生命周期由unique_ptr
内的Manager
管理,但客户端可以根据需要通过shared_ptr
访问对象。是的,这个共享指针可以变成悬空,但这是要求中固有的。
如果shared_ptr
使用的要求实际上是可以协商的,我会看到三种方法:
让Manager
暂停unique_ptr<Test>
并发出Test*
(这些观察员都可以)。记录他们的生命周期由经理明确管理,如果持有时间过长,他们就会变得悬空。
关注@ MikeSeymour的回答,让Manager
保持shared_ptr
并发出weak_ptr
s。记录Manager
只能保证drop()
如果客户的行为遭到破坏,并且不会永久锁定weak_ptr
。
发出类似于QPointer
的智能指针,当对象被销毁时,它会被设置为null。
我更喜欢#1;对我来说,感觉是最简单的事情。作为观察者,原始指针非常精细,如果你有明确的生命周期管理,你总是冒险在某处晃动指针。所以只需记录好并接受它。
答案 2 :(得分:0)
auto test = mng.createTest(50);
// here the count should be 2 and not 1
// one by the list's member and one by test
DEBUG_MSG("test : " << test.use_count());
test->fn();
mng.drop(test);
DEBUG_MSG("test : " << test.use_count());
当我调用mng.drop(test)时,在我的代码中- 仍然引用计数为1,因此对象不会被破坏。
这是因为您仍然坚持test
,当您致电mng.drop
时,您会向其提供test
的副本,从而将引用计数从n增加到n + 1.现在它完成所有操作,将引用计数减少2:一次用于局部变量ptr
,一次用于列表中的一个,但是你持有的那个仍然存在。
您也要发布对它的引用
test.reset();
这应该使引用计数为0.您将能够看到析构函数消息被打印。