6

関数の実行が終了すると、関数のそのスタックに割り当てられた変数にアクセスできなくなることを知っています。ただし、ベクター型は、割り当て方法に関係なく、要素をヒープに割り当てます。たとえば、

vector<int> A;

スタックの代わりにヒープにその要素のスペースを割り当てます。

私の質問は、次のコードがあると仮定します。

int main(int argc, char *argv[]) {
    // initialize a vector
    vector<int> A = initVector(100000);

    // do something with the vector...

    return 0;
}


// initialize the vector
vector<int> initVector(int size) {
    vector<int> A (size);  // initialize the vector "on the stack"

    // fill the vector with a sequence of numbers...
    int counter = 0;
    for (vector<int>::iterator i = A.begin(); i != A.end(); i++) {
        (*i) = counter++;
    }

    return A;
}

メイン関数でベクトル A を使用すると、メモリ アクセスの問題が発生しますか? これを数回試したところ、すべて正常に機能しましたが、これは運が良かったのではないかと心配しています。

私が見ているように、ベクトル A はその要素をヒープに割り当てますが、スタック自体に割り当てられたいくつかの「オーバーヘッド」パラメーター (おそらくベクトルのサイズ) があります。したがって、メイン関数でベクトルを使用すると、これらのパラメーターが別の割り当てによって上書きされると、メモリ アクセスの問題が発生する可能性があります。何か案は?

4

3 に答える 3

6

「Aを返す」を行う場合。値で返すので、ベクトルのコピーを取得します。C++は新しいインスタンスを作成し、そのインスタンスでcopyコンストラクターまたはoperator=を呼び出します。したがって、この場合、メモリをどこに割り当てたかは関係ありません。とにかくそれをコピーして古いコピーを破棄する必要があるためです(いくつかの可能な最適化にもかかわらず)。

ベクトル(および他のすべてのSTLコンテナー)のデータも値によって移動されるため、整数へのポインターではなく、整数のコピーを格納します。つまり、オブジェクトは任意のコンテナ操作で数回コピーでき、コピーコンストラクタや代入演算子を正しく実装する必要があります。C ++はデフォルトでそれらを生成します(すべてのメンバー変数でcopy ctorを呼び出すだけです)が、常に正しいことを行うとは限りません。

ポインターをSTLコンテナーに保管する場合は、共有ポインターラッパー(std::shared_ptrまたはboost::shared_ptr)の使用を検討してください。それらは、メモリが正しく処理されることを保証します。

于 2012-04-06T18:24:53.697 に答える
1

vector<int> A =はい、要素のメモリが割り当てられ、それが変数の構築に使用されるため、正常に機能します。ただし、パフォーマンスに関しては、これは最良のアイデアではありません。

ただし、関数を次のように変更することをお勧めします

void initVector(vector<int>& a, int size) 

使用法に関するその他の参照については、関数から STL ベクトルを返す…</a> および[C++]関数からベクトルを返す を参照してください。

パフォーマンスに関する追加のリファレンス (C++11 を使用) については、C++0x で関数呼び出しから std::vector を返す適切な方法 (セマンティクスを移動)を参照してください。

于 2012-04-06T18:08:12.553 に答える
0

C++ ベクトルには、実際には 1 つのポインターでリンクされた 2 つのメモリがあります。最初のものはスタックにあり、2 番目のものはヒープにあります。したがって、単一のオブジェクトにスタックとヒープの両方の機能があります。

std::vector<int> vec;
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
std::cout << sizeof(vec) << std::endl;

そのコードを実行すると、スタック領域に要素が含まれていないことに気付くでしょうが、まだ存在しています。そのため、関数から別の関数にベクトルを渡す場合、スタック領域を操作する必要があり、ベクトルは他のスタックベースのオブジェクトと同様にコピーされます。

于 2012-04-06T18:33:47.067 に答える