[英]How to have const members in stl container values in C++?
我希望使C ++成员变量成为const,如果一旦构造对象后就不应该更改它们,则有时需要通过STL对其进行修改。 例如,如果我有一个带有const成员的类的向量,并且尝试交换向量中的两个元素,则STL尝试使用默认生成的operator=()
并且由于const成员变量而失败。
我觉得operator=()
就像构造函数一样,正在创建整个对象,因此我想以某种方式允许operator=()
同时保留我的const成员变量。
无论如何,在C ++ 03中可以做到这一点吗? 如果没有的话,那么在C ++ 11中,也许是就地构建的?
class Foo {
const int _id;
static int _generate_unique_id();
public:
Foo()
: _id(_generate_unique_id()) {
}
};
vector<Foo> foo_vector;
// Fill foo_vector with several entries:
// [...]
// Try to swap the first and second elements of the vector:
swap(*foo_vector.begin(), *(foo_vector.begin() + 1));
// The above fails to compile due to const member variable _id
// prohibits us from using the default assignment operator.
用于在标准库容器中存储不可分配的对象的解决方案是存储指向对象的(智能)指针。 并非总是理想的,但可行的。
例如,如果我有一个带有const成员的类的向量,并且尝试交换向量中的两个元素,则STL尝试使用默认生成的operator =(),并且由于const成员变量而失败。
实现“三分之三”(默认和复制构造函数,赋值运算符和swap),如果_id则赋值运算符显式跳过重新分配。
您想要的是类似Java不变语言的东西。 这对于指针(以及由此而来的垃圾收集语言)来说真是太棒了,而对像C ++这样的价值语义语言来说却太棒了。
您有两种解决方案:
成员是私有的(或者应该是私有的),所以只有类本身(及其朋友)可以修改它。 因此,您所需要做的就是确保没有人在您所控制的类中做任何事情,并且在受保护的/公共的接口中不提供任何方式让其他人这样做。
TL; DR:使您的对象为非常量。 不要在类中修改它。 添加一个常量获取器。 卸下二传手(如果有)。
现在,我们遵循Java习惯用法。 该对象是const,但是可以重新分配指针,这正是您想要的。
实际上,这比const Data *
成员替代方法更好,因为它具有异常安全性。
有一个建议。
正如sehe首先提到的, 不要这样 。
您的目的是提高代码的质量,这意味着您的代码将需要在一处或另一处处于异常安全状态。 手动使用对象生命周期将使其无法在质量代码中使用。
阅读有关该主题的Herb Sutter文章: http : //www.gotw.ca/gotw/023.htm
成员上的const
不仅会阻止程序员在其生命周期内修改成员的值; 它还通过指定尝试对其进行修改的尝试是未定义的行为来实现编译器优化(请参阅const成员和赋值运算符。如何避免未定义的行为? )。
一种实现您想要的方式的方法是编写一个提供语义const
的nonmodifiable
容器,同时让您成为程序员来修改所包含的值:
template<typename T> class nonmodifiable {
T t;
public:
nonmodifiable(T t): t{std::move(t)} {}
operator const T &() const { return t; }
nonmodifiable &operator=(const nonmodifiable &) = delete;
};
您现在可以编写:
class Foo {
nonmodifiable<int> _id;
// etc.
};
并且因为_id
或其包含的值都不是const
,所以请使用destruct-placement新舞重新分配其值:
Foo &operator=(const Foo &foo) {
if (this != &foo) {
_id.~nonmodifiable<int>();
new (&_id) nonmodifiable<int>(foo._id);
}
return this;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.