2016-08-16 21 views
8

在下面的代碼,「情況1」作品如預期所測試的所有 編譯器,但是「情況2」似乎基於編譯器的行爲方式不同 用過的。不明原因的差異複製和修改時的std ::字符串

作爲示例MSVC具有SIT1和sit2產生相同的結果,然而 使用gcc /鐺和libstdC++時,該修改發生到 原始字符串和它的副本(有點像一個COW字符串)即使 我在使用C++ 11開關構建。

#include <iostream> 
#include <string> 

int main() { 

    // situation 1 
    { 
     std::string x0 = "12345678"; 
     std::string x1 = x0; 

     char* ptr = &x0[0] + 3; 

     (*ptr) = ' '; 

     std::cout << "1. x0: " << x0 << "\n"; 
     std::cout << "1. x1: " << x1 << "\n"; 

     if ((&x0[0]) == x0.data()) std::cout << "1. ptrs are equal\n"; 

    } 

    // situation 2 
    { 
     std::string x0 = "12345678"; 
     std::string x1 = x0; 

     char* ptr = const_cast<char*>(x0.data() + 3); 

     (*ptr) = ' '; 

     std::cout << "2. x0: " << x0 << "\n"; 
     std::cout << "2. x1: " << x1 << "\n"; 

     if ((&x0[0]) == x0.data()) std::cout << "2. ptrs are equal\n"; 
    } 

    return 0; 
} 

GCC(6.1)

1. x0: 123 5678 
1. x1: 12345678 
1. ptrs are equal 
2. x0: 123 5678 
2. x1: 123 5678 
2. ptrs are equal 

MSVC(2015)

1. x0: 123 5678 
1. x1: 12345678 
1. ptrs are equal 
2. x0: 123 5678 
2. x1: 12345678 
2. ptrs are equal 

是否有任何理由各種編譯器之間的行爲的差異 - 鑑於& X0 [0]和.data()返回相同的地址?

+0

[This GCC 6.1](http://melpon.org/wandbox/permlink/cJZq0ey2qv526sJU)的行爲是正確的。 –

+5

你真的不得不用'Z'替代'4'嗎?你能不能找到更難以區分的東西,比如'l'和'I'?在SO上提出問題的一半樂趣讓任何人都很難找到重要的細節。 –

+2

我真的希望你這樣問,因爲你正在移植你自己寫的古老可怕的代碼。 –

回答

15

情況2個原因未定義的行爲:

char* ptr = const_cast<char*>(x0.data() + 3); 

(*ptr) = 'Z'; 

std::basic_string::data說明書(C++ 14 [string.accessors]/3):

要求:程序應不改變存儲在字符數組中的任何值。

換句話說,你不可以通過由data()c_str()返回的指針丟掉const和修改字符串。

+0

但指針地址是一樣的嗎?並沒有標準說x0.data()和&x0 [0]應該是相同的? –

+0

@JacobiJohn他們應該是相同的地址,但是您只能通過'&x [0]'版本進行修改。對於copy-on-write實現,'operator []'將會修改副本以防結果被修改,但'.data()'不會。 –

+0

@ M.M可修改,未修改。代碼無法知道它是否會被修改。換句話說,即使對結果沒有進一步處理,非常量字符串實例/引用上的''x [0]''也會導致複製。 –