2012-04-06 11 views
7

私は、関数のスタックに割り当てられた変数は、関数の実行が終了するとアクセスできなくなることを知っています。しかし、ベクトル型は、どのように割り当てられても、その要素をヒープに割り当てます。したがって、たとえば、"スタック"に割り当てられたベクトルを関数から関数に渡すことはできますか?

vector<int> A; 

は、スタックの代わりにヒープ上にその要素のための領域を割り当てます。

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

+1

あなたのロジックでは、 'int add(int a、int b){int r = a + b;あなたの 'initVector'と同じ問題があるはずです... – delnan

+0

' A(size); '=>' A 'はスタック上にありますが、ポインタが指すメモリ位置はヒープ上にあります。 'size'個の連続したメモリ位置はヒープ上にあり、ベクトルクラスはヒープ上の先頭要素へのポインタを保持します。誰かが私を訂正するかどうかを見てみましょう。 – Mahesh

+0

TBH、私はこの種のことにも幾分混乱してきました。私が疑問を持ったときはいつも、私はベクトルも割り当てました。例えば、 'ベクトル * a; a =新しいベクトル; 'ポインタを返します。 –

答えて

1

はい、要素のメモリが割り当てられ、それがvector<int> A =変数を構築するために使用されるため、正常に動作します。しかし、パフォーマンスは賢明ですが、それは最良のアイデアではありません。私は使用方法の参照の場合

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

かかわらず、次のことがあなたの機能を変更することをお勧め

Returning a STL vector from a function…[C++] Returning Vector from Functionを参照してください。あなたがない場合は、Proper way (move semantics) to return a std::vector from function calling in C++0x

+0

RVOはおそらく提案された変更を不要にするでしょう。とにかくそれは良い練習です。 –

+0

リンクありがとうございます。私はこれがより良い方法であることに同意します。私はちょうどベクトルクラスが実際にどのように動作するかについて常に疑問を抱いていました。 – alguru

+0

@josephthomas私はあなたの方法(すなわち、ベクトルを参照によって渡す)を使うと、 'a = new vector 'を使ってベクトルを割り当てなければなりませんか?それともその周りに道ができますか? – alguru

4

を参照してください(C++ 11を使用して)、パフォーマンスに関する追加参考

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

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

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

0

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

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

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

関連する問題