2016-11-11 3 views
-1

テキストサイズが等しい場合にポインタが同じになることが理解できませんでした。 firstStringObj :: c_str()は前のポインタを上書きしているようです。std :: string :: c_str()は、関数によって返された前のものを上書きします。

#include <iostream> 
#include <string> 
#include <string> 
#include <stdio.h> 

std::string getConstCharAndModifyItWithANewString(const char* constchar) 
{ 
    std::string stringAtStack(constchar); 
    stringAtStack += "::isModified"; 
    return stringAtStack; 
} 

int main() 
{ 
    const char* firstConstCharPointer = getConstCharAndModifyItWithANewString("Hi!").c_str(); 
    std::string firstStringObj = "Hi+"; 

    printf(" firstConstCharPointer(%s)(%p)\nfirstStringObj(%s)(%p)\n\n", firstConstCharPointer,firstConstCharPointer, firstStringObj.c_str(),  firstStringObj.c_str() ); 
} 

OUTPUT: firstConstCharPointer(こんにちは+)(0x4593eb8) firstStringObj(+こんにちは)(0x4593eb8)

+0

は、コンパイラの最適化問題のように見えます。 gccで起こらない4.9.2 – ilo

+2

あなたは未定義の動作を観察しているので、最適化を責めることはできません。また、 '.c_str()'のドキュメントを読んでください – milleniumbug

+0

長い文字列では起こりません。 – ilo

答えて

1

std::stringオブジェクトを返します。 firstConstCharPointer変数が割り当てられ、式が完了すると、その一時オブジェクトは破棄され、割り当てられたメモリブロックが解放され、変数は解放されたメモリをポイントしたままになります。これは、ダングリングポインタとして知られています。

firstStringObjは次にが一時std::stringが以前に割り当てられ、解放されたのと同じメモリブロックを再利用する起こる新しいメモリブロックを割り当てます。だから、つかの間のポインタが有効なメモリを再度指し示すようになります。そのため、printf()ステートメントは、両方の文字列に同じメモリアドレスと内容を表示できます。

しかし、これはの定義されていない動作です。毎回割り当てられるメモリブロックは、完全に文字列のAllocatorまでです。 2番目のstd::stringはまったく別のメモリブロックを簡単に割り当てることができます。そして、無効なメモリを指し示している手掛かりのないポインタを逆参照しようとすると、クラッシュする可能性が高くなります。

あなたのコードが動作するためには、あなたが例えば、一時std::stringが正しくコピーされますので、std::stringオブジェクトにfirstConstCharPointerを変更する必要があります。

#include <iostream> 
#include <string> 
#include <cstdio> 

std::string getConstCharAndModifyItWithANewString(const char* constchar) 
{ 
    std::string stringAtStack(constchar); 
    stringAtStack += "::isModified"; 
    return stringAtStack; 
} 

int main() 
{ 
    const std::string firstConstStringObj = getConstCharAndModifyItWithANewString("Hi!"); 
    std::string secondStringObj = "Hi!"; 

    std::printf(" firstConstStringObj(%s)(%p)\nsecondStringObj(%s)(%p)\n\n", firstConstStringObj.c_str(), firstConstStringObj.c_str(), secondStringObj.c_str(), secondStringObj.c_str()); 
} 
4

ポインタがfirstConstCharPointerはダングリングポインタであるので、それは解放済みメモリを指して、ご使用のプラットフォーム上で同じです。

getConstCharAndModifyItWithANewStringによって返されたstd::stringが代入式const char* firstConstCharPointer = ...;の後に破棄されたためです。

したがって、新しいstd::stringオブジェクトを作成すると、コンパイルで前のstd::stringオブジェクトと同じメモリ位置が使用されるため、ポインタは同じになります。

私のプラットフォームでは、ポインタは同じで、Ideoneにはありません。

3

古典的な未定義の動作があります。 printf%sのためにfirstConstCharPointerを逆引きしようとします。このポインタの寿命に関連付けられstd::stringを割り当てた後に停止するために破壊されたデータにfirstConstCharPointer点:

const char* firstConstCharPointer = getConstCharAndModifyItWithANewString("Hi!").c_str(); 
// temporary std::string returned from getConstCharAndModifyItWithANewString destroyed, pointer becomes dangling. 
3

documentation:

に述べたように

c_strから得られたポインタは、()によって無効にされてもよいです。任意の標準ライブラリ関数に文字列への非const参照を渡す

  • 、又は
  • 演算子[]、at()、front()、back()、begin()、rbegin()、end()およびrend()を除く、文字列上の非constメンバー関数の呼び出し。

デストラクタが非constメンバ関数であり、上記のリストに表示されていないように、あなたは、無効なポインタを使用しています。

関連する問題