質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.36%

  • C++

    2412questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

文字が出力されない.

解決済

回答 4

投稿 2017/11/29 06:24

  • 評価
  • クリップ 0
  • VIEW 185

aglkjggg

score 600

発生している問題・エラーメッセージ

str2が正しく出力されません。

1~3は同じ事を別の書き方でしているだけと考えていましたが、
str2が出力されないことからこの考え間違っていた事がわかりました。
しかし、何故出力されないのかが理解できません。

何故出力されないかの解説または、調べる方法等を教えてください。

該当のソースコード

#include <iostream>

int main()
{
    // 1. OK
    auto str1 = std::string("abc");
    std::cout << str1.c_str() << std::endl;

    // 2. NG
    auto str2 = std::string("abc").c_str();
    std::cout << str2 << std::endl;

    // 3. OK
    std::cout << std::string("abc").c_str() << std::endl;
    return 0;
}

実行結果

補足情報(言語/FW/ツール等のバージョンなど)

Windows 10 64bit 1703
Visual Studio 2017
Windows SDK version 10.0.16299.0
プラットフォームツールセット Visual Studio 2017 (v141)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+6

str2が指している先が一時オブジェクトだからだと考えられます。
std::string("abc").c_str()においてstd::string("abc")オブジェクトは.c_str()によってconst char*を返した後は破棄されます。よってその後にstr2で指された領域にアクセスしてはいけません。
以下のケース22と同様と考えてもよいと思います。

ちなみに最近似た質問が上がっていたので参照ください。
string(5, 'A')で起きていることについて(C++)

#include <iostream>
int main()
{
    // 1. OK
    auto str1 = std::string("abc");
    std::cout << str1.c_str() << std::endl;

    // 2. NG
    auto str2 = std::string("abc").c_str();
    std::cout << str2 << std::endl;

    // 22. NG
    const char* str22;
    {
        std::string tmp = std::string("abc");
        str22 = tmp.c_str();
    }
    std::cout << str22 << std::endl;

    // 3. OK
    std::cout << std::string("abc").c_str() << std::endl;
    return 0;
}


あ、ideoneでは全部出力されますね。
未定義動作なので何が起きても不思議ではありませんが。

投稿 2017/11/29 09:22

編集 2017/11/29 09:26

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/29 10:12

    > 未定義動作なので何が起きても不思議ではありませんが。

    完全に処理系依存ですね。
    VC++のbasic_stringの実装は、メンバ変数に16バイトのバッファ領域を持っていて、そこに収まる短い文字列に関してはヒープを使わずにパフォーマンスを稼ぐ、ということをしています。そして、デストラクタでそのバッファ領域の先頭に0を書いています。したがって、"abc"のように短い文字列だと、オブジェクトが破棄された直後のc_str()が返したアドレスには0が入っていることになりご質問のような現象が発生します。

    16文字以上の長い文字列にすると結果が変わります。その場合、文字列はヒープに格納され、Releaseビルドなら領域解放後も中身は残されるので直前に設定した文字列がそのまま出力されます。Debugビルドだとデバッグコードが領域内を特定値で埋め尽くすので、変な文字列が出力されることになります。

    basic_stringもデバッグビルド時は内部バッファを特定値で埋め尽くすような実装にしていれば、ご質問のようなバグを発見しやすいのですけどね。

    キャンセル

  • 2017/11/29 10:32

    >そのバッファ領域の先頭に0を書いています。
    なるほど。空文字列として出力されるのですね。
    >デバッグビルド時は内部バッファを特定値で埋め尽くすような実装にしていれば
    16バイトのバッファ領域があるなら「you are fool!!!」とかでもよいかも(w

    キャンセル

  • 2017/11/29 11:28

    can110さん、catsforepawさん
    ご回答ありがとうございます。

    特にcatsforepawさん、非常に詳細な情報ありがとうございます。
    VisualStudioのデバッグとウォッチを利用するとおっしゃる通りの動作が確認できました。

    ありがとうございます、深い理解を得ることが出来ました。

    https://i.imgur.com/zhHmNa2.png

    キャンセル

  • 2017/11/29 11:32

    横から失礼します。
    この構文なら、str2はC言語文字列からコンストラクトされる筈です。C言語文字列用のコンストラクタはchar const *で受け取るので当然一時オブジェクトを渡せる筈。
    でも、実際には可笑しくなるし。最適化のための特別仕様があるのかも? 難易度高そうな気がします。
    https://wandbox.org/permlink/gtvipHottCewLZ0Y

    キャンセル

  • 2017/11/29 11:45

    Chironianさん

    何か勘違いをされているのでしょうか?

    > auto str2 = std::string("abc").c_str();

    この場合、str2は`const char *`で定義されるので、can110さんの書かれたコード例の「str22」とほぼ等価です。不正なコードであることは一目瞭然だと思うのですが……。

    キャンセル

  • 2017/11/29 11:56

    私はautoの型推論について以下のように素直に考えました。
    c_str()によりconst char*が返されるのですからstr2は「const char*」型だと。
    たしかにc_str()によってナル文字終端のC言語文字列が生成されると考えられます。
    そして、その戻り値の型const char*を引数とする「何か」のコンストラクタにより「何か」のオブジェクトが生成できるかもしれません。
    しかしその「何か」は「std::string」とは限らず推論できないと考えます。

    キャンセル

  • 2017/11/29 13:03

    > c_str()によりconst char*が返されるのですからstr2は「const char*」型だと。

    えーと、そういう話?
    それならそれで合っていると思います。autoの型推論は関数テンプレートの引数と同じはずなので、右辺値がconst char*なら、autoの型もconst char*になります。なってくれないと困ります。

    キャンセル

  • 2017/11/29 13:10 編集

    あああ、そっかそうでした。単純にstr2をstd::string型を思い込んでました。お二方、ありがとう。

    キャンセル

  • 2017/11/29 13:19

    autoについての理解が足りないので
    「str2 = std::string("abc").c_str()」でもしかして何か別の型のオブジェクトが生成される可能性もあるのかな?と新たな疑問が生じていました。が、それはないですね。
    catsforepawさん、Chironianさんコメントありがとうございました。

    キャンセル

+1

こんにちは。

str2はもう破壊されたメモリーを指しているので何も出力しないんです。
もう詳しく説明すると、

auto str2 = std::string("abc").c_str();

まず、str2は const char *になります。
そして、std::string("abc")用一時オブジェクトが生成されて、
c_str()で、その一時オブジェクトの内側にあるpointerがstr2に代入されます。
最後にstd::string("abc")用一時オブジェクトは破壊されます。
なのでstr2はinvalid状態になり何が出力されるか分かりません。

(蛇の足)
str1は std::string タイプになります。
なので一時オブジェクトがコピーされますのでオッケーです。
3の場合は一時オブジェクトが破壊される前に出力されます。なのでそれもオッケーです。

投稿 2017/11/29 09:37

編集 2017/11/29 10:00

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/29 12:17

    ご回答ありがとうございます。
    処理順序に従って書いていただき分かりやすかったです。

    キャンセル

-2

ワーニングは出るけど実行出来ますね・・・環境の問題か?

kondo@usr~/test >c++ tst01.cpp 
tst01.cpp:6:5: warning: 'auto' type specifier is a C++11 extension
      [-Wc++11-extensions]
    auto str1 = std::string("abc");
    ^
tst01.cpp:6:5: warning: 'auto' type specifier is incompatible with C++98
      [-Wc++98-compat]
    auto str1 = std::string("abc");
    ^~~~
tst01.cpp:10:5: warning: 'auto' type specifier is a C++11 extension
      [-Wc++11-extensions]
    auto str2 = std::string("abc").c_str();
    ^
tst01.cpp:10:5: warning: 'auto' type specifier is incompatible with C++98
      [-Wc++98-compat]
    auto str2 = std::string("abc").c_str();
    ^~~~
4 warnings generated.
[実行結果]
kondo@usr~/test >./a.out 
abc
abc
abc
kondo@usr~/test >cat tst01.cpp 
#include <iostream>

int main()
{
    // 1. OK
    auto str1 = std::string("abc");
    std::cout << str1.c_str() << std::endl;

    // 2. NG
    auto str2 = std::string("abc").c_str();
    std::cout << str2 << std::endl;

    // 3. OK
    std::cout << std::string("abc").c_str() << std::endl;
    return 0;
}


「追記」
str2に何が入るかデバッガで追いかけるのが得策かとd^^
あ!、stringをインクルードするか、c_str()呼ぶかしないとcoutには出せません。

投稿 2017/11/29 06:48

編集 2017/11/29 06:55

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/29 07:10

    回答ありがとうございます。
    WSLで確認した所動きました…
    VC++側の何らかの問題の気がしてきました><

    https://i.imgur.com/QgysesS.png

    gcc version 5.4.0 20160609

    キャンセル

  • 2017/11/29 10:22

    > VC++側の何らかの問題の気がしてきました

    いいえ、can110さんの回答が正しいです。そちらを読んでください。gccで実行できているように見えるとしたら、むしろその方が問題なのです。

    キャンセル

  • 2017/11/29 10:59

    can110さんの回答がまだ来てない状態で、g++でコンパイルした物だと動作したので「VC++側の問題」かと思いました><

    キャンセル

  • 2017/11/29 11:01

    あぁ、そうでしたか。コメントの前後関係までは見ていませんでした。失礼しました。

    キャンセル

-2

GCC/G++でコンパイルするときに
-std=c++11 を付けなければ当然ながらコンパイルエラーになります。

autoというのは型推論ですので。 

投稿 2017/11/29 08:51

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/29 08:55 編集

    回答ありがとうございます。
    しかし、今回質問させて頂いた件はstr2が正しく出力されない原因についてです。
    コンパイルエラーやautoについては問題が発生していません。

    また、開発環境は補足情報で明記してる通りWindowsでVisualStudioを利用しています。
    gcc/g++は利用していません。

    str2が正しく出力されない原因について何かわかりましたら教えて頂ければと思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.36%

関連した質問

同じタグがついた質問を見る

  • C++

    2412questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。