提问人:Bill Kotsias 提问时间:3/21/2018 更新时间:3/22/2018 访问量:100
仅创建 const 对象的 const 副本
Make only const copies of a const object
问:
我有一个包含引用的类,例如:
class A {
A(B &b) : b(b) {} // constructor
B &b;
}
有时 b 必须是只读的,有时它是可写的。当我制作一个对象时,很明显我想保护其中的数据。
但是,偶然的是,很容易制作对象的非常量副本,这将使其中的数据容易受到攻击。const A a(b);
const
const A a(b); // b object protected here
A a_non_const(a);
a_non_const.b.non_const_function(...); // b not protected now
我认为我应该以某种方式阻止对象的副本,当它是这样的:const
const A a(b);
const A a2(a); // OK!
A a_non_const(a); // Compiler error
这可能吗?
答:
2赞
tevemadar
3/21/2018
#1
您可以为堆执行此操作:
static const A *constCopy(const A &a); // and of course implement it somewhere
这样你就不会意外地通过你得到的指针修改对象(必须存储在 中,否则编译器会抱怨)。const A *
但是,它不适用于基于堆栈的对象,因为返回局部变量是一个相当致命的操作,并且“const 构造函数”尚未被发明(相关:为什么 C++ 没有 const 构造函数?const A &
)
2赞
Daniel Jour
3/21/2018
#2
代码中的缺陷:即使有const
类型限定符管理对类型的成员函数的访问以及对其成员的访问。由于您的成员是引用,因此在这里对您没有多大作用:无论哪种方式,初始化后都无法更改引用。您如何访问该引用的目标甚至没有考虑:const
B & b
const
const A a(b);
a.b.non_const_function(); // OOPS, no problem!
使用模板的解决方案
您可以向类型添加一个“标志”,而不是 (ab) 使用类型限定符,以区分需要具有非常量访问权限的情况和不需要访问的情况:const
#include <type_traits>
struct B {
void danger() {
}
void all_fine() const {
}
};
template<bool Writeable>
struct A {
using BRef = typename std::conditional<Writeable, B &, B const &>::type;
BRef b;
A (BRef b) : b(b) {};
};
using ConstA = A<false>;
using NonConstA = A<true>;
int main() {
B b;
ConstA a(b);
//NonConstA nc_a(a);
ConstA another_a(a);
//another_a.b.danger();
another_a.b.all_fine();
NonConstA a2(b);
a2.b.danger();
}
使用某些功能,您可以有选择地启用/禁用成员功能,具体取决于它们是否需要“可写”。std::enable_if
A
b
真正的解决方案:重构您的设计
但我想进一步强调这条评论:
“有时 b 必须是只读的,有时它是可写的。”你所有的问题都源于这种奇怪的二元性。我建议为你的类选择一组语义,而不是两组
您可能应该考虑拆分您的类,以便您拥有 a 和 a 都使用的功能(名称很糟糕,但我希望您理解我的意思)。CommonA
WriteableA
NonWriteableA
评论
0赞
Bill Kotsias
3/22/2018
你是对的,我没有给出完整的故事。我有这个“设计”,您将 b 返回为 const 或 non-const,如下所示:,反正我不是很喜欢!B& Get_b() { return b };
const B& Get_b() const { return b; }
评论