std::move对std::string的使用是否保证.c_str()返回相同的结果?

7

我希望提供零拷贝、基于移动的API。我想将一个字符串从A线程移动到B线程。在理念上,移动应该能够简单地将数据从实例A传递/移动到新的实例B,最小化或不进行任何复制操作(主要是地址)。因此,所有的数据指针等数据将被简单地复制,而不是通过移动构造函数构造新的实例。那么,std::string上的std::move是否保证在移动之前的实例和通过移动构造函数创建的实例上.c_str()返回相同的结果?


5
std::move 只是一种类型转换,它本身并不会执行任何操作。 - Kerrek SB
请记住,const 表示线程安全,因此除非这种假设的实现保护整个内容,否则是不允许的。 - Johan Lundberg
哎呀,const并不总是意味着线程安全。你必须查看类的实现才能确定这一点——例如,“mutable”保留了逻辑上的常量性,但不保证物理上的常量性,并且绝对不是线程安全的。 - Dale Wilson
2
C++标准库的类和函数是线程安全的,因为它们允许访问const方法而无需外部同步。只有在仍然保持正确行为(原子或以其他方式同步,如果必须)或者as-if的情况下,才允许const方法改变内部状态(可变或去除const)。http://herbsutter.com/2013/01/01/video-you-dont-know-const-and-mutable/ - Johan Lundberg
1
C++中的字符串通常具有小字符串优化。如果移动后的字符串的c_str相同,由于字符串对象的内部缓冲区具有不同的地址,因此无法进行小字符串优化。所以反过来想:如果标准要求在移动字符串时.c_str()保持相同,则无法进行小字符串优化。 - Bonita Montero
显示剩余4条评论
4个回答

13

不需要使用动态分配,也没有任何特定的动态分配要求。实际上,现代的实现通常将短字符串存储在string对象内,不分配任何内容;然后移动操作与复制相同。

需要记住的是,std::string虽然看起来很像容器,但它实际上不是一个容器。容器对于其元素有比std::string更强的保证。


所以例如 std::vector 的情况下,移动后我们保证指针将指向相同的位置的第一个元素? - DuckQueen
@DuckQueen:我也不是很确定。标准规定,在移动后目标容器的值与移动前的操作数相同,但这有点模糊。只有在swap中才明确表示不会触及任何容器元素。 - Kerrek SB

8
不,这并不是保证的。
如果保证了,就基本上禁止了短字符串优化。在其中一种情况下,整个短字符串的内容都存储在字符串对象本身中,而不是分别在堆上分配内存。
至少目前来说,我认为短字符串优化被认为非常重要,委员会极其不愿意禁止它(但这可能会改变——当最初的C++98标准编写时,他们花费了相当大的力气来允许写时复制字符串,但现在已被禁止)。

3

不需要,但如果需要,一种选择是将字符串放入std::unique_ptr中。个人而言,我通常不会仅依赖于c_str()值的本地范围。

例如,如有需要,可提供以下示例:

#include <iostream>
#include <string>
#include <memory>

int main() {
    std::string ss("hello");
    auto u_str = std::make_unique<std::string>(ss);
    std::cout << u_str->c_str() <<std::endl;
    std::cout << *u_str <<std::endl;
    return 0;
}

如果你没有使用C++14的make_unique函数。
auto u_str = std::unique_ptr<std::string>(new std::string(ss));

或者您可以直接从S.T.L.的提案中复制整个实现:链接 这里有一个示例,展示如何实现:Ideone 示例

如何将字符串放入unique_ptr中并按值传递? - DuckQueen

1
这里有文档因此你可以假设在某些条件下c_str()的结果是稳定的。
然而,在移动后不能假设c_str()仍然相同。实际上,对于长字符串它将保持不变,但对于短字符串,它将不会保持不变。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接