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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C++

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

Q&A

解決済

4回答

1939閲覧

C++ デストラクタが想定より一回多く機能している理由を教えて欲しいです!

YUKI007BKB

総合スコア10

C++

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

0グッド

2クリップ

投稿2019/06/10 07:21

C++初心者で拙い質問かもしれませんが,教えていただきたいです.

デストラクタに慣れるために,色々と自分でプログラムを組んで試していたのですが,下記のようなプログラムを実行した際,abcの前にデストラクタが二回呼び起こされている理由を教えていただきたいです.

getKitty関数内の Kitty obj が破壊されるので,abcの前にデストラクタは一回しか呼び起こされないと思うのですが,なぜ二回なのでしょうか?

どなたか分かる方いらっしゃいましたら答えていただけると助かります.

C++

1#include <iostream> 2using namespace std; 3 4class Kitty { 5public: 6 const char *str; 7 ~Kitty(); 8}; 9 10Kitty::~Kitty() { 11 cout << "口からバズーカ ( ̄□ ̄)\n"; 12} 13 14Kitty getKitty(const char *in) { 15 Kitty obj; 16 obj.str = in; 17 cout << obj.str; 18} 19 20int main() { 21 getKitty("Kitty on your lap\n"); 22 cout << "abc/n"; 23 return 0; 24} 25

result

1Kitty on your lap 2口からバズーカ ( ̄□ ̄) 3口からバズーカ ( ̄□ ̄) 4abc

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

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

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

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

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

guest

回答4

0

abcの前にデストラクタが二回呼び起こされている理由

return 文 - cppreference.comより

return 文なしに値を返す関数 (main を除く) の終わりに達した場合、動作は未定義です。

とのことです。実際の動作としては、皆さんの回答のようになっていると考えられます。


(また、C++17 以降でも NRVO は保証されないようです。)

(参考 -> 値のコピー省略を保証 - cpprefjp C++日本語リファレンス

投稿2019/06/10 19:13

編集2019/06/10 20:18
alphya

総合スコア124

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

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

Chironian

2019/06/11 01:53

> C++17 以降でも NRVO は保証されないようです。 あら、本当ですね。RVOだけなのですね。回答を修正させていただきます。
guest

0

ベストアンサー

こんにちは。

getKitty()関数は、Kettyクラスのインスタンスを返却しています。(参照でもポインタでもない)
この場合、return時に自動的にKettyクラスが(恐らくデフォルト・コンストラクタで)コンストラクトされ、getKitty()関数呼び出しを含む文の終了時にデストラクトされます。

例えば、int型を返却していたら呼び出し側では、それを受け取る一時領域が確保され、文の終了時に解放されます。それとほぼ同じですが、クラスのインスタンスの場合は開放時にデストラクタが呼ばれます。

C++

1Kitty getKitty(const char *in) { 2 Kitty obj; 3 obj.str = in; 4 cout << obj.str; 5 return obj; 6}

かなりややこしい話があるのですが、上記のようにすることで、obj 領域がそのまま返却されますので、デストラクタは1回しか呼ばれないケースが多いです。

微妙な差で2回呼ばれることもありますので、微妙な表現をしてしまいました。
所謂RVOが機能するケースではC++17より前は処理系によって1回だけ呼ばれ、C++17以降では1回が保証される。NRVO/RVOが機能できないケースでは複数回呼ばれます。
YUKI007BKBさんのコードは、NRVOが機能して1回だけのデストラクタ呼び出しになっていますので、C++17でも1回だけ呼び出しが「保証」されるというわけではないようです。


【alphyaさんの回答を見て修正しました】
てっきりNRVOについてもコピー省略が保証されると理解していましが、どうも異なるようです。
alphyaさんのリンク先を見るとRVOについてのみ記載されてました。

投稿2019/06/10 07:58

編集2019/06/11 02:00
Chironian

総合スコア23272

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

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

YUKI007BKB

2019/06/12 02:19

皆さん回答ありがとうございます. 色々と参考にさせてもらって実験してみたらなんとなく性質がわかりました. どの方をBAに選ぶか迷いましたが,一番丁寧でわかりやすかったChironianさんにさせていただきました. 他の方々もありがとうございました!
guest

0

Kitty getKitty(const char *in) {

これがKittyオブジェクトを返しているため

c++

1int main() { 2 Kitty kitty = getKitty("Kitty on your lap\n"); 3 cout << "abc/n"; 4 return 0; 5}

や、

c++

1void getKitty(const char *in) { 2 Kitty obj; 3 obj.str = in; 4 cout << obj.str; 5}

などを試してみるとよいでしょう

投稿2019/06/10 07:30

asm

総合スコア15147

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

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

0

この関数で返り値がないというwarningが出ています

Kitty getKitty(const char *in) { Kitty obj; obj.str = in; cout << obj.str; }

想像ですが、objで1回め、返り値を自動生成するためにtmpとしてKittyが生成されて2回めがでているのではないかと思います

投稿2019/06/10 07:28

izmktr

総合スコア2856

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問