メソッドから配列を返すにはどうすればよいですか? また、どのように宣言する必要がありますか?
int[] test(void); // ??
メソッドから配列を返すにはどうすればよいですか? また、どのように宣言する必要がありますか?
int[] test(void); // ??
int* test();
ただし、ベクトルを使用するのは「より C++」です。
std::vector< int > test();
編集
いくつかの点を明確にします。C++ ということでnew[]
anddelete[]
演算子を使いますが、malloc/free も同様です。
最初のケースでは、次のように記述します。
int* test() {
return new int[size_needed];
}
ただし、関数のクライアントは、返される配列のサイズを実際には認識していないため、クライアントは への呼び出しで安全に割り当てを解除できますが、これは良い考えではありませんdelete[]
。
int* theArray = test();
for (size_t i; i < ???; ++i) { // I don't know what is the array size!
// ...
}
delete[] theArray; // ok.
より良い署名は次のようなものです:
int* test(size_t& arraySize) {
array_size = 10;
return new int[array_size];
}
クライアントコードは次のようになります。
size_t theSize = 0;
int* theArray = test(theSize);
for (size_t i; i < theSize; ++i) { // now I can safely iterate the array
// ...
}
delete[] theArray; // still ok.
これは C++ でstd::vector<T>
あるため、広く使用されているソリューションです。
std::vector<int> test() {
std::vector<int> vector(10);
return vector;
}
オブジェクトによって処理されるため、を呼び出す必要はありません。次のようdelete[]
に安全に反復できます。
std::vector<int> v = test();
std::vector<int>::iterator it = v.begin();
for (; it != v.end(); ++it) {
// do your things
}
これはより簡単で安全です。
C++ メソッドで配列を返す方法と、それを宣言する方法を教えてください。int[] テスト (無効); ??
これは簡単な質問のように思えますが、C++ にはかなりの数のオプションがあります。まず、優先する必要があります...
std::vector<>
、実行時に遭遇する多くの要素に動的に成長する、または
std::array<>
(C++11 で導入)、コンパイル時に指定された要素数を常に格納します。
...メモリを管理するため、正しい動作が保証され、物事が大幅に簡素化されます。
std::vector<int> fn()
{
std::vector<int> x;
x.push_back(10);
return x;
}
std::array<int, 2> fn2() // C++11
{
return {3, 4};
}
void caller()
{
std::vector<int> a = fn();
const std::vector<int>& b = fn(); // extend lifetime but read-only
// b valid until scope exit/return
std::array<int, 2> c = fn2();
const std::array<int, 2>& d = fn2();
}
返されたデータへの参照を作成することで、コピーを回避できる場合もありますが、通常は、戻り値の最適化、または移動セマンティクス (C++11 で導入された)にconst
依存することができます。vector
array
組み込みの配列を本当に使用したい場合(上記の標準ライブラリ クラスとは異なりarray
ます)、1 つの方法は、呼び出し元がスペースを確保し、関数にそれを使用するように指示することです。
void fn(int x[], int n)
{
for (int i = 0; i < n; ++i)
x[i] = n;
}
void caller()
{
// local space on the stack - destroyed when caller() returns
int x[10];
fn(x, sizeof x / sizeof x[0]);
// or, use the heap, lives until delete[](p) called...
int* p = new int[10];
fn(p, 10);
}
別のオプションは、配列を構造体でラップすることです。これは、生の配列とは異なり、関数から値で返すことが合法です。
struct X
{
int x[10];
};
X fn()
{
X x;
x.x[0] = 10;
// ...
return x;
}
void caller()
{
X x = fn();
}
上記から始めて、C++03 の使用に行き詰まっている場合は、C++11 に近いものに一般化することをお勧めしますstd::array
。
template <typename T, size_t N>
struct array
{
T& operator[](size_t n) { return x[n]; }
const T& operator[](size_t n) const { return x[n]; }
size_t size() const { return N; }
// iterators, constructors etc....
private:
T x[N];
};
もう 1 つのオプションは、呼び出された関数がヒープにメモリを割り当てるようにすることです。
int* fn()
{
int* p = new int[2];
p[0] = 0;
p[1] = 1;
return p;
}
void caller()
{
int* p = fn();
// use p...
delete[] p;
}
ヒープ オブジェクトの管理を簡素化するために、多くの C++ プログラマは、オブジェクトへのポインターがスコープを離れたときに確実に削除されるようにする「スマート ポインター」を使用します。C++11 の場合:
std::shared_ptr<int> p(new int[2], [](int* p) { delete[] p; } );
std::unique_ptr<int[]> p(new int[3]);
C++03 に行き詰まっている場合、最適なオプションは、boost ライブラリがマシンで利用できるかどうかを確認することboost::shared_array
です。
さらに別のオプションは、によって予約された静的メモリを持つことfn()
ですが、これはスレッドセーフではありません。これは、 への各呼び出しがfn()
、以前の呼び出しからのポインタを保持している誰かが見るデータを上書きすることを意味します。とはいえ、単純なシングルスレッド コードには便利 (かつ高速) です。
int* fn(int n)
{
static int x[2]; // clobbered by each call to fn()
x[0] = n;
x[1] = n + 1;
return x; // every call to fn() returns a pointer to the same static x memory
}
void caller()
{
int* p = fn(3);
// use p, hoping no other thread calls fn() meanwhile and clobbers the values...
// no clean up necessary...
}
C++ 関数から配列を返すことはできません。8.3.5[dcl.fct]/6:
関数には、型配列または関数の戻り値の型があってはなりません[...]
最も一般的に選択される代替手段は、クラスが配列を含むクラス型の値を返すことです。
struct ArrayHolder
{
int array[10];
};
ArrayHolder test();
または、静的または動的に割り当てられた配列の最初の要素へのポインターを返すには、返されたポインターが指す配列の割り当てを解除する必要があるかどうか (必要な場合は、その方法) をユーザーに示す必要があります。
例えば
int* test2()
{
return new int[10];
}
int* test3()
{
static int array[10];
return array;
}
配列への参照またはポインターを返すことは可能ですが、上記の方法のいずれよりも実用的な利点がなく、より複雑な構文であるため、非常にまれです。
int (&test4())[10]
{
static int array[10];
return array;
}
int (*test5())[10]
{
static int array[10];
return &array;
}
関数から配列を返したい場合は、関数を終了すると値がなくなるため、値がスタックに格納されていないことを確認する必要があります。
したがって、配列を静的にするか、メモリを割り当てます(または、それを渡しますが、最初の試行は void パラメータを使用します)。あなたのメソッドでは、次のように定義します。
int *gnabber(){
static int foo[] = {1,2,3}
return foo;
}
「C++ メソッドで配列を返す方法と、それを宣言する方法は? int[] test(void); ??」
template <class X>
class Array
{
X *m_data;
int m_size;
public:
// there constructor, destructor, some methods
int Get(X* &_null_pointer)
{
if(!_null_pointer)
{
_null_pointer = new X [m_size];
memcpy(_null_pointer, m_data, m_size * sizeof(X));
return m_size;
}
return 0;
}
};
int のためだけに
class IntArray
{
int *m_data;
int m_size;
public:
// there constructor, destructor, some methods
int Get(int* &_null_pointer)
{
if(!_null_pointer)
{
_null_pointer = new int [m_size];
memcpy(_null_pointer, m_data, m_size * sizeof(int));
return m_size;
}
return 0;
}
};
例
Array<float> array;
float *n_data = NULL;
int data_size;
if(data_size = array.Get(n_data))
{ // work with array }
delete [] n_data;
int の例
IntArray array;
int *n_data = NULL;
int data_size;
if(data_size = array.Get(n_data))
{ // work with array }
delete [] n_data;