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

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

新規登録して質問してみよう
ただいま回答率
85.48%
String

Stringは、ゼロ以上の文字から連続してできた文字の集合を扱うデータ型です。基本的にテキストを表すために使われます。

C++

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

Q&A

解決済

1回答

17851閲覧

C++で参照渡しをするとstringの中身が消える

hamayanhamayan

総合スコア8

String

Stringは、ゼロ以上の文字から連続してできた文字の集合を扱うデータ型です。基本的にテキストを表すために使われます。

C++

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

0グッド

0クリップ

投稿2017/11/27 12:12

編集2017/11/27 17:45

問題

以下のソースコードを実行すると正しく"a"と出力されます。

cpp

1#include <vector> 2#include <iostream> 3#include <string> 4using namespace std; 5 6class Test { 7public: 8 string s; 9 Test(string s) : s(s) { } 10 string toString() { 11 return s; 12 } 13}; 14class Test2 { 15public: 16 Test t; 17 Test2(Test t) : t(t) { } 18 string toString() { 19 return t.toString(); 20 } 21}; 22 23int main() { 24 Test2 t(Test("a")); 25 cout << t.toString() << endl; 26 27 // 終了待ち用 28 getchar(); 29}

この中のTest2クラスを以下の様に変えると何も出力されずに終了します。

cpp

1class Test2 { 2public: 3 Test &t; 4 Test2(Test &t) : t(t) { } 5 string toString() { 6 return t.toString(); 7 } 8};

できればTest2 t(Test("a"));のように初期化をしたく、かつ、参照渡しをしたいのですが、2番目のクラスではなぜ何も出力されずに終了するのでしょうか。
それとも参照渡しは諦め、値渡しかポインタ渡しをした方が良いのでしょうか。

###補足情報(言語/FW/ツール等のバージョンなど)
環境は
Visual Studio Community 2017 Version 15.1 (26403.7) Release
.NET Framework Version 4.7.02046
です。

ご助力よろしくお願いいたします。

解決後追記: lvalueとrvalue

これでコンパイルが通ってしまうのはVisual Studioの独自仕様らしい。
C++の仕様の観点からもこの代入は正しくない。
本の虫: rvalue reference 完全解説

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

LouiS0616

2017/11/27 15:32

『もう参照渡しとは言わせない』の記事を完全に読み誤っているようです。Javaのいわゆる『参照渡し』(正確には参照の値渡し)はどちらかと言うとポインタ渡しに近いですし、記事ではStringが特殊であることを否定しています。
hamayanhamayan

2017/11/27 17:41

混乱を避けるため、欄ごと削除しました。ありがとうございます
guest

回答1

0

ベストアンサー

C++ではstringはただのクラスなので特別扱いなどはありません。
その他のクラスと動作は全く同じです。

C++

1Test2 t(Test("a"));

こうするとTestは一時的に作られてTest2のコンストラクタを抜けた時点で破棄されます。
そのためt.tは破棄されたTestを示していてtoStringを呼び出した時点での動作は未定義です。
クラッシュしてもおかしくありません。
TestをTest2よりも後で破棄されるよう、

C++

1Test t("a") 2Test2 t2(t);

とそれぞれを生存するようにするか、以下のようにTestをコピーするしかないです。

ついでに、toStringでstringがコピーされるのでconst&で返すほうがいいと思います。

C++

1class Test { 2public: 3 string s; 4 Test(string s) : s(s) { } 5 const string& toString() const { 6 return s; 7 } 8}; 9class Test2 { 10public: 11 Test t; // ここを参照にしない 12 Test2(const Test& t) : t(t) { } // ここでtはコピーされる 13 const string& toString() const{ // const&で返せばcoutではコピーされない 14 return t.toString(); 15 } 16};

投稿2017/11/27 12:24

toki_td

総合スコア2850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hamayanhamayan

2017/11/27 13:50

納得な回答ありがとうございます! この短時間でこのクオリティの回答は驚きです。
yohhoy

2017/11/27 17:00 編集

> string部分をintに変えると参照渡しでも正しく表示されました。 補足:厳密にはint&型でも正しく動作する保証はありません。たまたま期待通りの結果が得られただけです。理由はtoki_tdさん回答の通りで、参照(int&)が指す先(int)の方が先に破棄されてしまうためです。(いいかえると、メモリの残骸を見てしまっています)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問