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

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

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

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

Q&A

4回答

1515閲覧

make_unique : C++14のやり方は「改善」ですか、それとも「改悪」?

insecticide

総合スコア315

C++

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

0グッド

0クリップ

投稿2022/06/23 04:51

編集2022/06/25 06:04

C++

1// C++14以前ではstd::unique_ptrとnewを利用する場合、以下のコードを書きました。 2std::unique_ptr<C> c(new C()); 3 4// C++14でstd::make_uniqueを使用する場合、newは不要になります。 5auto v1 = std::make_unique<C>(); 6

コードとして前者のほうは形式的な一貫性並びに概念的な明確性があって、コードの簡潔さも後者より優れますね。

「make_unique」を導入するメリットは何でしょうか。

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

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

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

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

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

Zuishin

2022/06/23 05:00

> コードの簡潔さも後者より優れますね。 そうですか?
insecticide

2022/06/23 05:39

まあ、"C"の文字数が多い場合、確かに後者のほうは短いですね。
Zuishin

2022/06/23 05:49

文字数もそうですし、同じことを二度書くという冗長性で比べても、構文の複雑度で比べても、後者の方がシンプルだと思います。 前者が勝っているのは、型名が一文字の時の文字数だけで、私には他に見当たりません。 一貫性や概念的な明確性においても、episteme さんの回答の通りのように思います。 > コードとして前者のほうは形式的な一貫性並びに概念的な明確性があって、コードの簡潔さも後者より優れますね。 この部分の説明があれば、そこに焦点を当てた回答が得られるのではないでしょうか。
episteme

2022/06/23 07:48 編集

短く書ける より 正しく動く が優先 だと思うけどなー 前者は int n; std::unique_ptr<int> n_ptr(&n); // やっちゃダメ! を許しちゃうよね。
MasakiHori

2022/06/24 01:33

Objective-Cには全く関係のない話なのでタグを外してください
insecticide

2022/06/24 04:12

> Objective-Cには全く関係のない話 そうですか 《Objective-C》はC++の標準化機関と関係ないのでしょうか
Zuishin

2022/06/24 04:16 編集

タグの説明には次のように書かれています。 https://teratail.com/tags/Objective-C > Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。 次の表現は、もっとどうにかならなかったのかと思いますが。 > Smalltalkが取り入れられています。
insecticide

2022/06/24 04:20

早速お返答ありがとうございます > Smalltalkが取り入れられています。 笑
MasakiHori

2022/06/25 05:21 編集

Objective-CとC++が別の言語であることは理解できましたか? 理解できましたらObjective-Cのタグを外してください
guest

回答4

0

前者のほうは形式的な一貫性並びに概念的な明確性があって

...そうですか?

unique_ptr 使えば delete不要となります。
であれば、(deleteに対応する)newもなくなる make_unique 使う方が一貫性に優れるのでは?

投稿2022/06/23 05:27

episteme

総合スコア16614

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

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

insecticide

2022/06/23 05:57

そうですか。 ご教授本当にありがとうございます。 そうであれば、逆に、「NEW」と「delete」を無くして、「unique_ptr」と「make_unique」に統一されるほうが良いですね!
episteme

2022/06/23 07:37 編集

コード中に new を見つけたら 対応する delete が唯一ひとつであるかを 確認/検証 したくなる/せにゃならん じゃないですか。 "never say delete" なら "never say new" も対になっててほしくありません?
guest

0

C++標準へのstd::make_uniqueの提案に理由が書かれています。
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3588.htm

  • 「コードに new delete を書くな」と言えるようになる。さいきんの C++ では「new delete が出てきたら妙なメモリ管理をしている可能性が高い」と見なされます。
  • unique_ptr<LongTypeName> up(new LongTypeName(args) はクラス名を2回書く必要があり、make_unique<LongTypeName>(args) の方がシンプル
  • foo(unique_ptr<X>(new X), unique_ptr<Y>(new Y)) のようなコードでは引数の評価順は実装依存で、X コンストラクタが例外を出すと new Yunique_ptr に入らずにリークする可能性がある

投稿2022/06/23 05:21

int32_t

総合スコア20884

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

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

0

コードの簡潔さも後者より優れますね

どこが/どう 優れるのか? を述べないと読み手に伝わらないのでは.
「前者は C という型名を2回書くけど後者は( auto を使えば )1回」という点を見れば後者の方が「簡潔」と言えるのでは.

make_unique 自体のメリットというのは,前者の書き方だと処理が

  1. new C
  2. unique_ptr のコンストラクタ

という2段階になるのに対して,後者は「1個関数呼び出し」という1段階な形になる,ということでしょう.

投稿2022/06/23 05:10

fana

総合スコア11658

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

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

fana

2022/06/23 05:15

何だっけ? 「前者」の書き方を関数引数に書いたような場合に,引数評価の最中に例外が起きたらどうの…みたいな話で > 1. new C の後, > 2. unique_ptr のコンストラクタ の完了まで(?)の間に例外やらが起きたときに new されたやつが delete されない可能性がある的な話だったような.
fana

2022/06/23 05:27 編集

手元の本に書いてあったハズ…ということで確認してました. Effective Modern C++ にこの点の解説が(make_shared を例にして)あります. (…っていう話まで,そのリンク先にありますね^^)
fana

2022/06/23 05:33 編集

関数引数の一方に この質問で言うところの「前者」の書き方を,他方に関数呼び出しを書いた場合が例になっています. f( shared_ptr<XXX>( new XXX() ), g() ); みたいな. (newの後で g() に行ってそこで例外が出ると…っていう)
insecticide

2022/06/23 05:40

"C"の文字数が多い場合、確かに後者のほうは短いですね。
insecticide

2022/06/23 05:53

皆様 ご教授ありがとうございます。 can110様よりご提示頂いたリンクは自分の疑問とぴったりですね。 良く分かりました。
can110

2022/06/23 06:09

> insecticide 樹海に行ってみたらすぐにリンクを見つけました。 欲しい答えがすでにあるかもしれませんので、質問立てる前に行ってみるとよいでしょう。
insecticide

2022/06/23 08:02 編集

>樹海に行ってみたらすぐにリンクを見つけました。 ごめんなさいね! 益々のご活躍をお祈り申し上げます
guest

0

C++ の型システムではスマートポインタの間違った使い方を必ずしも検出できません。 たとえば

cpp

1#include <memory> 2 3int main(void) { 4 int* foo = new int(); 5 std::unique_ptr<int> bar(foo); 6 std::unique_ptr<int> baz(foo); 7}

というようなプログラムは間違っていますが、コンパイルは出来てしまいます。 スマートポインタが管理する所有権はスマートポインタの間では上手く伝播されますが、生ポインタが間に入ると簡単に破綻してしまうのです。

故に可能な限り生ポインタが表出しない形、つまりオブジェクトの生成と同時にスマートポインタを作ってしまう (プログラマからは生ポインタが見えない) std::make_unique を使った方法はより良い作法であると考えられます。

投稿2022/06/23 09:02

SaitoAtsushi

総合スコア5446

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

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

insecticide

2022/06/23 10:48

ご指導ありがとうございます。 ************************************* 可能な限り生ポインタが表出しない形、つまりオブジェクトの生成と同時にスマートポインタを作ってしまう (プログラマからは生ポインタが見えない) std::make_unique を使った方法はより良い作法であると考えられます。 ************************************* 非常にシャープな考え方ですね。さすがです。 でも、 int* foo = new int(); std::unique_ptr<int> bar(foo); std::unique_ptr<int> baz(foo); これは何が悪いのでしょうか。
SaitoAtsushi

2022/06/23 11:11

「所有権」は「後始末 (delete) をする責任」という意味です。 このコードでは bar も baz もスコープの終わりでオブジェクトを解放しようと試みます。 つまり同じオブジェクトに対して二度の delete が試みられます。 その結果は未定義の挙動です。
insecticide

2022/06/24 04:26

> つまり同じオブジェクトに対して二度の delete が試みられます。 > その結果は未定義の挙動です。 あっ、そうですね! ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問