我的情况类似于包括:
class A
{
public:
A(shared_ptr<B>);
}
class B : public enable_shared_from_this<B>
{
const shared_ptr<A> a;
}
在构建之前,我无法shared_ptr
到B
,因此在初始化a
之前。所以,我需要在构造之后初始化我的常量字段(我认为它否认RAII),或者稍后构造它(因此它不能是const,所以它否定const-correctness,并且看起来也不太一致RAII)。
看起来像是常见的情况。有没有最干净的方法来处理这个?你会怎么做?
答案 0 :(得分:2)
我会通过没有const
成员来解决这个问题,简单明了。它们通常比它们的价值要大得多(例如,它们使得该类不可分配,甚至不能移动 - 可分配)。
a
是私有的,因此只有类本身才能访问它。因此,应该足以记录&#34; a
在初始化之后永远不应该被修改!!!&#34;。如果你担心自己不够(或者班级friend
超出你的控制范围),你可以更加明显地这样做:
class B : public enable_shared_from_this<B>
{
const std::shared_ptr<A>& a() { return _use_this_ONLY_for_initialising_a; }
std::shared_ptr<A> _use_this_ONLY_for_initialising_a;
};
答案 1 :(得分:2)
这种情况是重构代码的好指标。在找到解决此问题的方法之前,请考虑B
是否应该实际上来自A
或成为A
的成员...
..因为它可能会删除你对象的常量 - 并且可能不会使用shared_ptr(你有一个循环引用,所以单独ref-counting永远不能破坏你的对象!)。 / p>
答案 2 :(得分:0)
如果A
实际上没有保存您传递的shared_ptr<B>
副本(只是暂时使用B
),那么您可以将其工作(见下文)但是:< / p>
A
没有引用B
,那么它只能采用B&
或B*
参数,而不是shared_ptr<B>
,所以你应该改变设计。A
确实保留了引用,那么您将获得循环引用,因此您应该更改设计。这很有效,但实际上非常非常糟糕,很容易引入错误,通常是一个坏主意,我可能甚至不应该显示它,只是改变你的设计以避免循环依赖:
#include <memory>
#include <iostream>
class B;
class A
{
public:
A(std::shared_ptr<B> b);
};
class B : public std::enable_shared_from_this<B>
{
// return a shared_ptr<B> that owns `this` but with a
// null deleter. This does not share ownership with
// the result of shared_from_this(), but is usable
// in the B::B constructor.
std::shared_ptr<B> non_owning_shared_from_this()
{
struct null_deleter {
void operator()(void*) const { }
};
return std::shared_ptr<B>(this, null_deleter());
}
public:
B(int id)
: m_id(id), a(std::make_shared<A>(non_owning_shared_from_this()))
{ }
int id() const { return m_id; }
private:
int m_id;
const std::shared_ptr<A> a;
};
A::A(std::shared_ptr<B> b)
{
std::cout << b->id() << std::endl;
}
int main()
{
auto b = std::make_shared<B>(42);
}