迭代器和引用计数字符串

时间:2012-06-21 23:39:09

标签: c++ stl copy-on-write

如果我们考虑使用引用计数的std :: string实现,请考虑以下情况:

int main()
{
  string english = "Hello";
  string german  = english; //refcnt = 2
  string german2 = german;

  /* L1 */ german[1] = 'a';
  /* L2 */ *(german2.begin() + 1) = 'A';

  cout << english << endl << german << endl << german2 << endl;
  return 0;
}

L1和L2会发生什么?引用计数是否已损坏并执行了深层复制?我是这么认为的,但我担心如果发生这种情况,那就做一个简单的事了:

cout << german[1] << endl; 

或简单:

cout << *(german.begin()) << endl;
非const上下文中的

会执行不必​​要的深层复制。我对吗?这些实现如何处理这个细节?

2 个答案:

答案 0 :(得分:6)

你是对的,在所有四个例子(L1,L2和下面两个例子)中都会有一个副本,即使对于后两个例子也是如此。

不幸的是,当调用operator []的非const版本或取消引用非const迭代器时,实现无法判断生成的非const引用是否将用于修改对象,所以它必须安全地播放并制作副本。

C ++ 11向字符串和其他容器添加了函数cbegin()cend(),这些容器即使在非const对象上调用也会返回const迭代器。这有助于缓解这个问题。我不知道运营商[]的可比解决方案。

注意:让operator []或迭代器的运算符*()返回一个代理类型,正如其他一些回答者建议的那样,实际上不是一个选项,因为它打破了容器需求,其中一个是这些函数返回实际的引用。 (这就是为什么现在每个人都同意vector<bool>是一个错误 - 它以这种方式使用代理。)

(当然,如果您正在编写自己的引用计数类,那么就没有什么能阻止您使用代理类型来实现此目的。)

答案 1 :(得分:2)

实现这一目标的一种方法是通过代理类。所以当你索引到一个字符串而不是获得一个字符时,你会得到一个外观和感觉像char的对象。当对其执行写入时,它会导致原始字符串的深层复制。