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

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

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

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

Q&A

解決済

2回答

1852閲覧

ポインタのメンバ変数の初期化について

ten9

総合スコア15

C++

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

0グッド

0クリップ

投稿2018/11/06 16:30

c++

1/* hoge.hpp */ 2class Hoge { 3public: 4 Hoge::Hoge(); 5private: 6 std::shared_ptr<int> _value; 7};

上記のような場合、_valueはコンストラクタで初期化すべきなのでしょうか。コンストラクタでは例外を投げないような設計にすべき、と多くの場所で見てきたので、ポインタをコンストラクタで初期化すべきではないのでは、と考えました。どう対処すべきかわかりません。

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

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

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

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

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

guest

回答2

0

ベストアンサー

Chironianさんが言っておられますが、コンストラクタで例外を投げるべきでないというのはあまり推奨される考え方ではないです。
コンストラクタはエラーが発生してもそれを戻り値で知らせることができないためです。
コンストラクタの処理時点ですでにクリティカルなエラーに陥っている場合、コンストラクタ内で例外を投げるべきなのです。

さて、コンストラクタで特に_valueにアクセスしないとしましょう。
何らかの理由で先に空のインスタンスを作り、SetValue()のようなセッターを用いて後から初期化できるようにしたい場合です。
次のように実際にポインタの未初期化がクリティカルになるまで例外送出を遅延する、コンストラクタでは例外を送出しないという戦略が考えられます。

cpp

1/* hoge.hpp */ 2class Hoge { 3public: 4 Hoge() = default; 5 void SetValue(std::shared_ptr<int> val) { _value = val; } 6 int DoSomething(){ 7 if (!_value) throw std::runtime_error("null!"); 8 int val = *_value; 9 // ... 10 return val; 11 } 12private: 13 std::shared_ptr<int> _value; 14};

もしくは、次のようにコンストラクタで初期化した時点から初期化を要求するという場合もあります。
個人的には、この場合を採用するのは

  • コンストラクタで初期化されたリソースをコンストラクタ内で早速使いたい、もしくは
  • リソースの初期化を一度きりに制限(つまりコンストラクタだけに)制限したい。

という需要からです。

cpp

1/* hoge.hpp */ 2class Hoge { 3public: 4 Hoge(std::shared_ptr<int> rsc): _value(rsc) { 5 if (!_value) throw std::runtime_error("construct error!"); 6 } 7 int DoSomething(){ 8 int val = *_value; 9 // ... 10 return val; 11 } 12private: 13 std::shared_ptr<int> _value; 14};

投稿2018/11/07 01:31

mitama_rs

総合スコア165

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

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

ten9

2018/11/07 11:10

確かにセッターを用いて上げてくださった例よりは、コンストラクタ内で例外を投げた方がよりスマートに書けそうです 回答ありがとうございました
guest

0

こんにちは。

_valueはポインタのように振る舞いますが、クラス・インスタンスです。そのデフォルト・コンストラクタによる初期化でよければ、改めて初期化処理を記述する必要はありません。(コンパイラが自動的に生成しますので。)

コンストラクタでは例外を投げないような設計にすべき、と多くの場所で見てきた

かなりその記述は減ってきたと思うのですが、未だに数多くありますか。
確かにコンストラクタで投げた例外を適切に処理するのはちょっと難しいですが、コンストラクタはエラーを返却できないので例外を投げたくなることは非常に多いです。
コンストラクタから例外を投げないよう頑張るよりは、適切に例外を処理できるよう頑張る方が好ましいと思います。
スマート・ポインタを使えばそれほど難しくはないですし。


なお、デストラクタからは例外を投げない方が良いのは間違いないです。投げてはいけないというものではないですが、配列やコンテナに入れるとリークしますし、他にも問題が発生するシナリオが多数有り、それらを回避できる一般解は存在しないようです。

ですので、デストラクタから例外を投げないことは強く推奨されています。
C++11以降はデフォルトではデストラクタから例外を流出させると問答無用でプロセスが落ちます。それくらい強く推奨されています。

投稿2018/11/06 17:12

Chironian

総合スコア23272

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

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

ten9

2018/11/07 11:06

コンストラクタから例外を投げるのは設計としてちゃんとしたものだったのですね 回答ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問