2017-03-28 9 views
1

私の仕事は、T(テンプレート)コンストラクタを呼び出さずにテンプレート型の配列を作成することです。その後、std :: moveを使ってこの配列に値を移動したいどうすればC++でこれを行うことができますか?ここに私のコードです:C++コンストラクタを呼び出さずに配列を使用する

void *temp = malloc((end-begin) * sizeof(T)); 
for (unsigned int i = begin; i < end; ++i){ 
    temp[i] = std::move(array[i]); 
} 

しかし、それは仕事ではありません。コンパイラは次のように言っています:不完全な型 'void'へのポインタの添え字。

+3

Wow、C++ 11のタグ付きの生のmallocを使用していますか? –

+1

デバッグのヘルプ( "**なぜこのコードは動作しないのですか?**")は、 必要な動作、特定の問題またはエラー、最短のコードを含める必要があります**質問自体に** を再現する必要があります。 。 **明確な問題のない質問 ステートメント**は、他の読者には役に立ちません。参照:[最小、完全、および 検証可能な例の作成方法](http://stackoverflow.com/help/mcve) –

+3

*プレースメントnew *をご覧ください。 – Jarod42

答えて

2

voidの配列は意味をなさない。 voidは不完全なタイプ(サイズはありません)ですので、表示されているエラーはtemp[i]です。

あなたがしたいことを達成するには、std::vectorを使用してアイテムが利用可能になったときにアイテムを押し込むのはどうですか?

std::vector<T> temp; 
for (unsigned int i = begin; i < end; ++i){ 
    temp.push_back(std::move(array[i])); 
} 
-1

あなたが本当に手でそれをしたい場合は

T *temp = (T*) malloc((end-begin) * sizeof(T)); 
+0

@SanderDeDyckerが示すようにベクトルを使用すると、より安全です。 –

+3

これはポインタの型問題を解決しますが、 'T'が' std :: string'なら 'temp [i]'には文字列がありません。 –

1

を試してみてください、あなたは配置新しいを探しています。

unsigned char* buf = new unsigned char(end-begin); 

か:まず、unsigned char秒の「生のバッファ」に割り当てる

auto buf = std::make_unique<unsigned char[]>(end-begin); 

をして、あなたはnew (buf) Tnew (buf+sizeof(T)) Tnew (buf+2*sizeof(T)) Tのようなものは、そのメモリ空間にあなたのオブジェクトを「据え付ける」に書き込みます。

上記の例では、私はアライメント要件を完全に無視しています。これは危険です。

したがって、std::vectorのメモリプールを複製する代わりに、std::vectorを使用してください。

std::vector<T> vec; 
vec.reserve(end-begin); 
for (unsigned int i = begin; i < end; ++i){ 
    vec.push_back(std::move(array[i]); 
} 

です。

0

他の人が指摘しているように、voidには定義されたサイズがありません。は配列として索引付けできません。

temp[1]はどこから始まりますか?

のナイーブ修正:

コードは代入演算子を呼び出し、非自明かどうだろう

temp[i] = std::move(array[i]);

T *temp = std::malloc((end-begin) * sizeof(T));

はと組み合わせて使用​​する場合と同じように悪いですごみに作用するときには失敗する。それはtemp[i]にある。たとえば、割り当てが明示的または暗黙的に割り当て先のリソースを割り当て解除すると、初期化されていないtemp[i]で動作し、失敗します。

If(IF!

std::memcpy(temp+i*sizeof(i),array[I],sizeof(T));

コードの行は、本質的にTは自明-コピー可能タイプであると仮定されていること:)あなたは正しいコードは次のようになり、これをやりました。

最初の行は、オブジェクトがTであると仮定していますが、デフォルトのコンストラクタは簡単です。 Tに些細なデフォルトのコンストラクタがある場合、ほとんどのコンパイラは要素の初期化を離れて最適化します(これは、アスカーが避けようとしているものです)。

ので(forループを使用して)お勧めのコードは次のとおりです。

T* temp= new T[end-being]; 
for(unsigned int i=begin;i<end;++i){ 
    temp[i-begin]=array[i]; 
} 

NB:このコードはまた、begin!=0壊れ元のコードのバグが修正されています。 arrayの中間からサブセクションをコピーして、tempの先頭にコードがコピーされているように見えますが、0tempで始まることを忘れてしまいます。

しかし、そのようなコピーを推奨C++のアプローチは、次のとおりです。

T* temp= new T[end-being]; 
std::copy(array+begin,array+end,temp); 

良い実装が決定し、可能な場合は任意のバルクメモリ操作を利用します。 有効であれば暗黙的にこれはstd::memmove(temp,array,(end-begin)*sizeof(T));になるはずです。コンパイラが認識しない場合があります

唯一の最後のねじれは、我々は、範囲ビーイングおろか(temparrayと重複することはできません知っているので、潜在的に、もう少し効率的

std::memcpy(temp,array,(end-begin)*sizeof(T));

、この場合には、実際に有効であるということですコピー)。

脚注:コメントで指摘したように、最も一般的なC++のアプローチは、これらの最適化をバックグラウンドで使用していると通常想定できるstd::vectorを使用することです。しかし、何らかの理由でアプリケーションを再構築することが不可能または望ましくない場合、この回答は、提供されたコードを書き直す有効な効率的な方法を提供します。

+0

まあ、C++のアプローチはベクトルを使用することです:) –

+0

@ TheTechel通常はtrueです。確かにフードの下では、 'std :: vector'がトリビアルに気づき、大量のコピーを使用し、実際に' std :: memcpy'を利用することを期待しています!しかし、 'std :: vector'の(ある程度の)オーバーヘッドがあり、ポスターにそれらを設定する何らかの理由がある場合、アプリケーションを記録せずに結果を達成する正しい方法です... 私はメモを作成します。 – Persixty

関連する問題