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

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

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

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

Q&A

解決済

1回答

2736閲覧

C++ N4189のUnique Resourceの実装例について

Chironian

総合スコア23272

C++

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

0グッド

0クリップ

投稿2016/04/27 03:27

編集2016/04/27 03:28

N4189で提案されているUnique Resourceが便利そうなので、簡易版を自ソフトへ取り込もうとしています。

この資料の16ページ 8.2 Unique Resourceに実装例が記載されているのですが、何か変です。

####疑問①

C++

1template<typename R,typename D> 2class unique_resource{ 3 R resource; 4 D deleter; 5 bool execute_on_destruction; // exposition only 6 7(中略) 8 9// construction 10explicit 11unique_resource(R && resource, D && deleter, bool shouldrun=true) noexcept 12 : resource(std::move(resource)) 13 , deleter(std::move(deleter)) 14 , execute_on_destruction{shouldrun}{} 15 16(中略) 17 18//factories 19template<typename R,typename D> 20auto 21make_unique_resource( R && r,D &&d) noexcept { 22return unique_resource<R,std::remove_reference_t<D>>( 23 std::move(r) 24 ,std::forward<std::remove_reference_t<D>>(d) 25 ,true); 26}

となっているのですが、std::move()しているためresourceに参照を渡せないように思います。

実験
普通に名前付きインスタンス(std::vector<unsigned> foo;のfoo)をfactoryに渡したところ、msvc 2015ではstd::move()のままでも通ったのですが、MinGW 5.2.0ではエラーになりました。

error: invalid initialization of non-const reference of type 'std::vector<unsigned int>&' from an rvalue of type 'std::remove_reference<std::vector<unsigned int>&>::type {aka std::vector<unsigned int>}'

そして、std::forward<>へ変更することでビルドと実行できるようになりました。
これは実装例のミスと考えて間違いないでしょうか?
私自身のstd::forwardの理解が浅いのでいまいち確信が持てないのです。

####疑問②
次に、factoryでremove_reference<D>されていますが、この必要性が分かりません。

実験
remove_reference_t<D>が2箇所にあります。このままでも動作するのですが、両方ともremove_reference_t<>をやめて、ラムダ式を与えてみたところ問題なく動作しました。
このremove_reference_t<>は不要と考えて間違いないでしょうか?

意味もなくコードが複雑になるのは好ましくないので、不要なら削除しようと思います。

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

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

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

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

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

guest

回答1

0

ベストアンサー

Unique Resourceは文字通り「Uniqueな/他と共有しない排他的な」資源を扱うため、参照を渡せないのは設計通りかと思います。

普通に名前付きインスタンス(std::vector<unsigned> foo;のfoo)をfactoryに渡したところ、msvc 2015ではstd::move()のままでも通ったのですが、MinGW 5.2.0ではエラーになりました。

MinGW 5.2.0の挙動が正しいはずです。オブジェクトは変数fooで既に管理されているため、そこからUnique Resourceを作ってはいけません/禁止されるべきです。


次に、factoryでremove_reference<D>されていますが、この必要性が分かりません。

make_unique_resource第二引数に左辺値を渡すケースで必要になると思います。

  • 1個目:このケースではテンプレートパラメータDは左辺値参照T&に推論されるため、unique_resource::deleterを非左辺値参照とするためのremove_reference_t<D>だと思います。
  • 2個目:std::forward<std::remove_reference_t<D>>(d)std::move(d)と等価なような... Give Up.

投稿2016/04/27 05:39

yohhoy

総合スコア6191

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

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

Chironian

2016/04/27 07:03 編集

yohhoyさん。ご回答ありがとうございます。 なるほど「unique_ptrをリソースへ拡張する」ような発想なのですね。 そして、std::move()で処理するためにfactoryの1個目はremove_reference<D>する必要があるということ納得です。2個目の方は確かに良く分からないですね。1個目と合わせた程度なのかも? そして、私が欲しいものはスコープから出る時に自動的に後始末するものだったので、微妙に異なるものだったということのようです。 クラス内のメンバ関数間で共有したいリソースなのでメンバ変数とし、特定のブロック内でのみメモリ確保させたかったのです。(参照型パラメータで次々と渡しても良いのですが、仕様変更時に無駄な手間がかかるので避けたかったのです。) 名前を変えて実装することにします。 お陰ですっきりしました。ありがとうございました。 【追記】 同じN4189に記載されているscope_exitが使えました。 単に後始末関数をこれに登録すればOK。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問