8

std::arrayこれは、スタック メモリとヒープ メモリの相互作用、およびstd::vectorクラスを介してスタックからヒープに移動する特定のケースに関する質問です。

原則std::array<T>として、最初の要素へのポインターと、配列のサイズに関するコンパイル時の情報を加えたものと見なすことができます。std::vector<T>その事実を考慮して、ポインターをコピーするだけarrayでの内容をに移動しようとするコンストラクターを持つことは可能でしょうか。vector

ユースケースは、std::array<double, >

std::array<double, 20> fun(){...};

std::vectorしかし、要素ごとにコピーする必要なく、後でそれを a に割り当てることにしました。

std::vector<double> v = fun(); // not working code

今、やらなければならないこと

std::array<double, 20> tmp = fun();
std::vector<double> v(tmp.begin(), tmp.end());

実際には、これが可能であれば不要な冗長な作業を行いますstd::vector<double> v(std::move(tmp)); \\ not working code

std::vectorとのメモリ配置はstd::array同じなので、 と の障害ではありません。

主な障害は、std::array要素がスタックにあり、std::vector要素がヒープにある可能性があることを理解しています。ムーブ コンストラクターを記述してもstd::vector、スタックからのメモリが取り返しのつかないほど破壊されることは明らかです。

したがって、この質問は次のようにも読めると思います。

メモリをスタックからヒープに移動する方法はありますか (それが何を意味するにせよ)、それを移動コンストラクタと組み合わせることができるかどうかは?

またはstd::vector原則として移動コンストラクターをstd::array?

MWE:

#include<array>
#include<vector>

std::array<double, 20> fun(){return {};} // don't change this function

int main(){
    std::array<double, 20> arr = fun(); // ok
    std::vector<double> v(arr.begin(), arr.end()); // ok, but copies and the allocation is duplicated
    std::vector<double> v2 = fun(); // not working, but the idea is that the work is not duplicated
}
4

2 に答える 2

4

メモリをスタックからヒープに移動する方法はありますか (それが何を意味するにせよ)、それを移動コンストラクタと組み合わせることができるかどうかは?

私は個人的に「それが何を意味するか」というビットが大好きです。これについて、しばらく考えてみましょう。スタックからヒープに何かを移動すると、スタックのその部分が突然ヒープ割り当て領域としてマークされ、通常の破壊の対象になることを意味します。

それに関する問題は、スタックが連続しており、スタックから物をうまくポップすることによって破壊されることです。「ねえ、このメモリビットを残して」とだけ言うことはできません-連続したスタックの割り当てと割り当て解除は、その部分を「飛び越える」必要があります。

説明する:

|                      |
|----------------------|
| stack block 1        |
|----------------------|
| your vector          |
|----------------------|
| stack block 2        |
|----------------------|
|-                    -|

これら 2 つのブロックをアンワインドしたい場合は、最初にスタック ポインターをブロック 2 ポインターのサイズだけ減らし、次にベクターとブロック 1 のサイズだけ減らす必要があります。これは実際には起こり得ないことです。

したがって、ここで実行可能な唯一の解決策は、ヒープ メモリ領域にコピーを作成することです。ただし、これらのコピーは、多くの人が予想するよりもはるかに高速です。ベクトルが数メガバイトであっても、メモリコントローラーはいくつかのページをスワップするだけで、データのビットに対応する電気信号を物理的に送信する必要はないと思います。

さらに、ベクトルのサイズを変更すると、いずれかの方法で再割り当てが必要になります。配列は必要なだけのメモリを正確に占有するため、単一の要素を追加するだけで、避けようとしているコピーがトリガーされます。

于 2015-12-01T11:29:47.077 に答える