如何保持常量正确性和RAII
How can I keep const-correctness and RAII?
我有类似于包含的情况:
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的正确性,而且看起来与RAII不太一致(。
这看起来很常见。有什么最干净的方法来处理这个问题吗?你会怎么做?
我会通过没有const
成员来解决这个问题,简单明了。它们通常比它们的价值要麻烦得多(例如,它们使类不可赋值,甚至不可移动(。
a
是私有的,所以只有类本身可以访问它。因此,它应该足以记录"a
在初始化后永远不应该被修改!!"。如果你担心这还不够(或者这个类有你无法控制的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;
};
这样的情况是重构代码的好指标。在找到解决这个问题的方法之前,想想B
是否应该真正继承A
或成为A
的成员。。。
因为它可能会消除对象的常量,并且可能不使用sharedptr(你有一个循环引用,所以单靠引用计数永远无法破坏你的对象!(。
如果A
实际上没有保存shared_ptr<B>
的副本,您可以传递它(只是短暂地使用B
(,那么您可以执行此操作(见下文(,但是:
- 如果
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);
}
相关文章:
- 具有瞬态资源的RAII类
- 代理对象的常量正确性
- std::函数常量正确性未遵循
- 使用RAII在给定次数的迭代后重新分配资源
- 违反const正确性:我应该现实地期待什么问题
- 在文件夹迭代上实现 RAII
- 在 RAII 构造中修改 RVO 值是否安全?
- C++ 常量正确性/缺少支持常量和非常量实例的类的常量构造函数
- RAII 等效于 FIFO 发布订单
- 当无法进行RAII时,如何在C++中"try/finally"?
- 如何处理 RAII 中的资源等待
- 自定义引用包装器的常量正确性
- c++重载=运算符,RAII
- 引用类型的数据成员提供有关恒常正确性"loophole"
- 初始化期间针对安全检查的指针的恒定正确性
- 如果我公开常量和非常量 API,我是否破坏了常量正确性?
- 如何使用 RAII 包装返回错误代码的 C 分配
- 如何强制实施有关指针数据成员的常量正确性
- 使用 RAII 替换最终块以释放内存
- 如何保持常量正确性和RAII