2

我喜欢将我的 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.
4

4 回答 4

0

在标准库容器中存储不可分配对象的一种解决方案是存储(智能)指向对象的指针。并不总是理想的,但可行。

于 2013-04-26T14:29:49.050 回答
0

例如,如果我有一个包含 const 成员的类的向量,并且我尝试交换向量中的两个元素,STL 会尝试使用默认生成的 operator=() 并且由于 const 成员变量而失败。

实现“三大半”(默认和复制构造函数、赋值运算符和交换),赋值运算符显式跳过重新赋值 if _id。

于 2013-04-26T14:33:40.873 回答
0

你想要的是像 Java 不可变习语这样的东西。这对于指针(因此,垃圾收集语言)非常棒,而对于像 C++ 这样的值语义语言则不那么棒了。

你有两个解决方案:

1 - 使您的对象在界面中不可变

该成员是私有的(或者应该是私有的),所以除了类本身(及其朋友)之外没有人可以修改它。因此,您需要做的就是确保没有人在类(您控制的)内做任何事情,并且在受保护/公共接口中没有提供任何方法让其他人有权这样做。

TL;DR:让你的对象非 const。不要在类内修改它。添加一个 const getter。移除二传手(如果有的话)。

2 - 使用 std::unique_ptr<const Data>

现在我们遵循 Java 习语。对象是 const,但指针可以重新归属,这正是您想要的。

这实际上比const Data *成员替代方案更好,因为它具有异常安全性。

奖励:不要手动调用析构函数来再次重建对象

有一个答案建议这样做。

正如sehe首先提到的那样,不要那样做

您的重点是提高代码的质量,这意味着您的代码需要在某一时刻保持异常安全。并且手动使用您的对象生命周期将使其在质量代码中无法使用。

阅读 Herb Sutter 关于该主题的文章:http ://www.gotw.ca/gotw/023.htm

于 2015-09-08T10:04:46.363 回答
-1

conston members 不只是阻止程序员在其生命周期内修改成员的值;它还通过指定修改它的尝试是未定义的行为来启用编译器优化(请参阅const 成员和赋值运算符。如何避免未定义的行为?)。

做你想做的事情的一种方法是编写一个nonmodifiable提供语义的容器,const同时让你作为程序员修改包含的值的可能性:

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 new dance 来重新分配它的值:

Foo &operator=(const Foo &foo) {
   if (this != &foo) {
      _id.~nonmodifiable<int>();
      new (&_id) nonmodifiable<int>(foo._id);
   }
   return this;
}
于 2013-04-26T14:46:36.997 回答