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

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

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

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

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

Q&A

解決済

2回答

2101閲覧

デフォルトアロケーターのconstructメンバ関数について

JADEN

総合スコア106

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

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

0グッド

0クリップ

投稿2016/03/18 13:43

編集2016/03/18 13:47

標題において、実装コードに疑問があります。

以下のコードのconstructメンバ関数で、placement newに渡すポインタをボイドポインターにキャストして渡しています。
なぜ、キャストしているのでしょうか。

また、new((void*)p) T(value)で、コピーコンストラクター?を呼んで、オブジェクトを構築していますが、なぜコピーコンストラクタを呼び出すのでしょうか。
デフォルトコンストラクターでは、不都合があるのでしょうか。

引用サイト: C++編(標準ライブラリ) 第28章 アロケータ

C++

1template <class T> 2class allocator 3{ 4public: 5 // 型定義 6 typedef size_t size_type; 7 typedef ptrdiff_t difference_type; 8 typedef T* pointer; 9 typedef const T* const_pointer; 10 typedef T& reference; 11 typedef const T& const_reference; 12 typedef T value_type; 13 14 // アロケータをU型にバインドする 15 template <class U> 16 struct rebind 17 { 18 typedef allocator<U> other; 19 }; 20 21 // コンストラクタ 22 allocator() throw(){} 23 allocator(const allocater&) throw(){} 24 template <class U> allocator(const allocator<U>&) throw(){} 25 // デストラクタ 26 ~allocator() throw(){} 27 28 // メモリを割り当てる 29 pointer allocate(size_type num, allocator<void>::const_pointer hint = 0) 30 { 31 return (pointer)( ::operator new( num * sizeof(T) ) ); 32 } 33 // 割当て済みの領域を初期化する 34 void construct(pointer p, const T& value) 35 { 36 new( (void*)p ) T(value); 37 } 38 39 // メモリを解放する 40 void deallocate(pointer p, size_type num) 41 { 42 ::operator delete( (void*)p ); 43 } 44 // 初期化済みの領域を削除する 45 void destroy(pointer p) 46 { 47 p->~T(); 48 } 49 50 // アドレスを返す 51 pointer address(reference value) const { return &value; } 52 const_pointer address(const_reference value) const { return &value; } 53 54 // 割当てることができる最大の要素数を返す 55 size_type max_size() const throw() 56 { 57 return numeric_limits<size_t>::max() / sizeof(T); 58 } 59};

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

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

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

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

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

guest

回答2

0

今さらですみません。

なぜ、キャストしているのでしょうか。

規格としてはキャストしないとまずいからです。
例えば、以下のようなオーバーロードをユーザが提供していた場合を考えてみてください。

C++

1void* operator new(size_t, int*);

この場合に、キャストせずに new(p) T(value) と書いてしまうと、標準ライブラリで提供されている ::operator new(size_t, void*) ではなく、ユーザが提供した ::operator new(size_t, int*) が呼ばれてしまいます。
それでは当初の目的が果たせないため、この場合の void* へのキャストは必須です。

デフォルトコンストラクターでは、不都合があるのでしょうか。

あります。
「デフォルト構築+コピー代入」の結果と「コピー構築」の結果が等しい保証は無いからです。
(場合によっては、コピー代入が不可な可能性すらあります)

いずれの質問についても、普通に使用している分には「そんなバカな」的な気がするかもしれませんが、標準ライブラリは使用される文脈が分からないため、対処可能な範囲でなるべくいつでも同じ挙動となるように注意深く実装されています。

投稿2018/09/21 08:44

kariya_mitsuru

総合スコア18

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

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

0

ベストアンサー

なぜ、キャストしているのでしょうか。

それは引用サイトの管理者に聞いてみないことには判りません。元々placement newの引数はvoid *なので、私ならいちいちキャストしたりはしませんが。引数がvoid *だから、合わせた方が良いかな、と考えたのでしょうか。

デフォルトコンストラクターでは、不都合があるのでしょうか。

不都合というか、デフォルトコンストラクターで初期化した後で、改めてオブジェクトの値をコピーすることになり、二度手間になってしまいます。

コピーコンストラクタで実装していれば、

C++

1construct(ptr, T()); 2construct(ptr, T(other)); 3construct(ptr, T(value)); 4construct(ptr, T(param1, param2));

このように一つのメソッドでどのようなコンストラクタにも対応できますが、デフォルトコンストラクタ(引数なし)にすると、

C++

1construct(ptr); // デフォルトコンストラクタならこれで済みますが 2 3construct(ptr); 4*ptr = T(other); // 改めて代入する必要が生じます 5 6construct(ptr); 7*ptr = T(value); 8 9construct(ptr); 10*ptr = T(param1, param2);

このようにコード量が増えてしまいます。また、場合によってはパフォーマンスにも影響するかもしれません。

投稿2016/03/18 14:15

catsforepaw

総合スコア5938

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

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

JADEN

2016/03/18 15:17 編集

catsforepawさん、いつも回答ありがとうございます。 例えば、 std::vector<type> vec; vec.push_back( type() ); の場合で、 void construct(pointer p, const T& value)のvalueは、type()であるという認識で正しいでしょうか。
catsforepaw

2016/03/18 15:23

はい、合ってます。
catsforepaw

2016/03/18 15:31 編集

あっと、すみません。厳密には違います。 vectorの`push_back`は ```C++ void push_back(const T& x); void push_back(T&& x); ``` このような宣言になっています。type()は一時オブジェクトが生成されて、下のメソッドが呼ばれます。そのxがallocatorのconstructメソッドに渡されることになります。
JADEN

2016/03/18 15:33

コピーコンストラクタを使用したnew(今回はplacement new)は、オブジェクトの構築にコピーコンストラクタを使用するということでしょうか。 コピーコンストラクタを使用したnewを、初めて見た気がしたので、戸惑いました。
catsforepaw

2016/03/18 15:51

オブジェクトの複製を作ることはごく普通に行われていることなので、newでコピーコンストラクタを使うことは、さほど珍しいことではないと思います。 placement newはそれ自体あまり使われることがないのですが、やはりコピーコンストラクタで初期化するのは一般的に行われていると思います。 STLのコンテナで内部的によく使われるallocatorは、その使用状況としてオブジェクトのコピーが多いので、必然的にコピーコンストラクタによる構築になるのだと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問