如果我们考虑使用引用计数的 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/