Xcode - STL字符串赋值中的浅拷贝

3
在 Xcode 中运行以下 C++ 代码时:
std::wstring str1 = L"1111";
std::wstring str2 = str1;

void* ptr1 = (void*)str1.c_str();
void* ptr2 = (void*)str2.c_str();

结果是两个指针相等。这符合标准吗? 在Visual Studio中情况并非如此。


你使用的Xcode版本是什么?我在Mac上使用Xcode/clang没有得到这个结果。 - Richard Hodges
Xcode 6.3.1 和 C++ 方言 gnu++11 (编译器选项:-std=gnu++11) - Ofer B
建议您使用-stdlib=libc++选项。它是更符合标准的实现,并且是新项目的默认选项。 - Richard Hodges
1个回答

2

看起来这个实现正在使用写时复制(COW)优化,其中字符串的内部状态只有在执行写操作时才真正设置*。这在C++11之前的实现中是允许的,但我认为自C++11以来不再是标准。

请注意,即使不写入数据,您也可以在非const方式下访问字符串时检查底层指针的地址是否发生变化:

str2[0];

对该表达式的求值应触发写操作,从而更改指针的地址。以下是一个可行的示例:

#include <string>
#include <iostream>

int main() 
{
  std::wstring str1 = L"1111";
  std::wstring str2 = str1;

  std::cout << (void*)str1.c_str() << " " << (void*)str2.c_str() << std::endl;

  str2[0]; // forces a write operation. c_str() changes.

  std::cout << (void*)str1.c_str() << " " << (void*)str2.c_str() << std::endl;
}

在最近的gcc版本中,这将产生以下结果。
0x8a8e014 0x8a8e014
0x8a8e014 0x8a8e03c

*一些非const的访问即使它们在语义上不改变字符串,也可能触发写操作,就像上面的例子所示。*

我们正在使用gnu++11方言,它与C++11不完全兼容,所以很可能是这种情况。谢谢! - Ofer B
1
@OferB 我认为gcc 4系列在COW方面不符合标准,即使在C++11或C++14模式下也是如此。至少在我几个月前检查时还是这样。 - juanchopanza

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