c++ - 迭代器和引用计数字符串

标签 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;

在非常量上下文中会执行不必​​要的深拷贝。我对吗?实现如何处理这个细节?

最佳答案

你是对的,将在所有四个示例(L1、L2 和下面的两个)中创建一个拷贝,即使对于后两个,它是不必要的。

不幸的是,当调用 operator[] 的非常量版本或取消引用非常量迭代器时,实现无法判断生成的非常量引用是否将用于修改对象, 所以它必须谨慎行事并制作拷贝。

C++11 添加的函数 cbegin()cend()到字符串和其他返回 const 迭代器的容器,即使在非 const 对象上调用也是如此。这有助于缓解问题。我不知道 operator[] 的类似解决方案。

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

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

关于c++ - 迭代器和引用计数字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11148355/

相关文章:

c++ - 我需要从 GetNamedSecurityInfo API 中释放哪些返回参数?

c++ - STL vector 和线程安全

c++ - pragma pack 一个 STL 容器

版本化文件的 svn 写时复制语义 : an svn:externals use case?

php - 写时复制会防止阵列上的数据重复吗?

c++ - 在C++中的for循环中,泛型索引的好名字是什么?

c++ - 在 C++ 中删除映射迭代器的行为不一致

C++ 如何将 STL 列表传递给函数

arrays - 为什么直接在 ArraySlice 上调用变异方法不会触发写时复制?

c++ - Qt 5.2 DLL 返回与调用 DLL 的应用程序不同的结果