9

众所周知,Qt 小部件使用隐式共享。所以我对 stl 容器也很感兴趣std::vectorstd::string也使用隐式共享。

如果不是,为什么?因为它非常有用。

如果答案是肯定的,我们如何确定呢?我需要简单的 C++ stl 程序,它表明 stl 容器使用隐式共享。复制时它不会进行深度复制。

4

4 回答 4

11

不,他们不能。当您尝试修改容器的内容,甚至在其上调用可变对象begin()时,这将意味着潜在的写时复制,从而使对容器的所有引用和迭代器无效。这将是一个难以调试的情况,并且是被禁止的。

尽管std::string从技术上讲它不是容器,但自 C++11 起仍然禁止进行写时复制:

引用 basic_string 序列元素的引用、指针和迭代器可能会因该 basic_string 对象的以下用途而失效:
...
— 调用非常量成员函数,除了 operator[]、at、front、back、begin、重新开始、结束和结束。

[字符串.要求]

...因为它非常有用。

呵呵,干嘛?通过引用传递几乎总能解决所有“性能问题”。原子引用计数在多处理器机器上本质上是不可扩展的。

于 2013-02-05T20:19:44.207 回答
4

除了其他人对容器中的 CoW 行为提出的反对意见之外,这里还有一些。这些都属于违反惯例的行为类别,因此会导致毫无戒心的开发人员出现奇怪的错误。

例外

允许 CoW 意味着容器上的无害突变操作可能会失败并出现异常,否则它们不会。这将是一个特殊的危险,operator[]无论是在一个std::vectorstd::string

穿线

人们可能合理地期望能够复制构造一个容器,其明确目的是将其交给另一个线程,而不必担心此后的并发性。CoW 并非如此。

于 2013-02-05T20:43:39.750 回答
3

正如在类似问题中注意到的那样:

C++ 标准不禁止或强制写入时复制或任何其他实现细节std::string。只要满足语义和复杂性要求,实现就可以选择它喜欢的任何实现策略。

我认为,对于std::vector

此外,您可能对这个主题感兴趣:如何实现 std::string

于 2013-02-05T20:15:32.880 回答
1

STL 容器不使用隐式共享。它们总是具有纯值语义。

原因在于运行时性能:在多线程程序(可能但不一定在多核主机上运行)中,管理数据的锁定开销(例如引用计数、写入前复制时锁定)远远超过纯值副本的开销,后者具有根本没有特殊的线程含义。预计将遭受巨大复制的程序std::maps实施显式共享以避免复制。

事实上,在 STL 的早期,std::string 确实使用了隐式共享。但是当第一个多核 CPU 出现时,它就被放弃了。

于 2018-07-04T15:24:36.777 回答