让我们说我有一个类,它是enable_shared_from_this的子类。这个基类的文档说在调用shared_from_this之前应该有一个共享指针拥有这个类。使用new分配类并调用shared_from_this来管理对象是否安全?
答案 0 :(得分:3)
来自标准:
§20.8.2.4
shared_ptr shared_from_this();
shared_ptr shared_from_this()const;
7 *要求:enable_shared_from_t这应该是T的可访问基类。这应该是一个 类型为T的对象t的子对象。至少应有一个拥有& t的shared_ptr实例。
8返回:与p。
共享所有权的shared_ptr对象r9后置条件:r.get()== this
如果您在不受shared_from_this()
管理的班级中致电shared_ptr
,则结果将是未定义的行为,因为您尚未完成其中一个已记录的先决条件方法
我从经验中知道,在[当前版本] libc ++中,结果是抛出异常。但是,与所有未定义的行为一样,不能依赖它。
答案 1 :(得分:2)
这个基类的文档说在调用shared_from_this之前应该有一个拥有这个[object]的共享指针。
好的,很酷。
使用new分配[object]并调用shared_from_this来管理对象是否安全?
没有。在调用shared_from_this之前,应该有一个拥有此[object]的共享指针。
答案 2 :(得分:1)
不,这不安全。如果对象由shared_from_this
管理,而不是通过shared_ptr
分配(没有关联的new
),则只应调用shared_ptr
。例如这段代码
struct Test: std::enable_shared_from_this<Test> {
std::shared_ptr<Test> getptr() {
return shared_from_this();
}
};
Test *test = new Test;
std::shared_ptr<Test> test2 = test->getptr();
将抛出std::bad_weak_ptr
(至少在使用libstdc++
时)。但这没关系:
std::shared_ptr<Test> test(new Test);
std::shared_ptr<Test> test2 = test->getptr();
答案 3 :(得分:1)
正如其他用户已经提到的,对不属于shared_from_this
的实例的shared_ptr
调用将导致未定义的行为(通常是异常,但没有保证)。
那么,为什么还有一个答案?
因为我曾经做过同样的问题并得到了几乎相同的答案,然后我开始挣扎于之后立即出现的另一个问题 - 我怎样才能保证所有实例都由{{1}管理}}
为了完整起见,我添加了另一个答案,并提供了有关这方面的一些细节 这是一个以前没有提到的简单解决方案。
确实如此简单的解决方案:私有构造函数,工厂方法和可变参数模板。 它遵循一个片段,在一个最小的例子中将所有这些片段混合在一起:
shared_ptr
基本的(琐碎的?)想法是禁止显式构造新实例,但是在这里使用名为#include<memory>
#include<utility>
class C: public std::enable_shared_from_this<C> {
C() = default;
C(const C &) = default;
C(C &&) = default;
C& operator=(const C &) = default;
C& operator=(C &&c) = default;
public:
template<typename... Args>
static std::shared_ptr<C> create(Args&&... args) noexcept {
return std::shared_ptr<C>{new C{std::forward<Args>(args)...}};
}
std::shared_ptr<C> ptr() noexcept {
return shared_from_this();
}
};
int main() {
std::shared_ptr<C> c1 = C::create();
std::shared_ptr<C> c2 = C::create(*c1);
std::shared_ptr<C> c3 = c2->ptr();
// these won't work anymore...
// C c4{};
// std::shared_ptr<C> c5 = std::make_shared<C>();
// std::shared_ptr<C> c6{new C{}};
// C c7{*c1};
// ... and so on ...
}
的工厂方法。
变量模板用于避免编写多种工厂方法,仅此而已。完美转发有助于我们以正确的方式做到这一点。
很简单,不是吗? 无论如何,我花了一段时间来弄清楚这一点,所以我希望这将有助于未来的读者遇到同样的疑问。