web-dev-qa-db-ja.com

関数から配列を返す方法は?

メソッドから配列を返すにはどうすればよいですか?また、どのように宣言する必要がありますか?

int[] test(void); // ??
44
ewggwegw

int* test();

しかし、ベクトルを使用するのは「more C++」です。

std::vector< int > test();

[〜#〜] edit [〜#〜]
いくつかのポイントを明確にします。 C++について説明したので、new[]およびdelete[]演算子を使用しますが、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
}

簡単で安全です。

57
Simone

c ++メソッドで配列を返すにはどうすればよいですか、どのように宣言する必要がありますか? int [] test(void); ?

これは簡単な質問のように聞こえますが、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();
}

返されたデータへのconst参照を作成することで、コピーを回避できる場合がありますが、通常は戻り値の最適化に依存するか、またはvectorではなくarray -移動セマンティクス(C++ 11で導入)。

inbuilt配列(上記の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::shared_arrayを提供します。

さらに別のオプションは、fn()によって予約された静的メモリを使用することです。ただし、これはTHREAD SAFEではありません。また、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...
}
17
Tony Delroy

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;
}
9
CB Bailey

関数から配列を返したい場合は、関数を離れると値が消えてしまうため、値がスタックに保存されないようにする必要があります。

そのため、配列を静的にするか、メモリを割り当てます(または渡すが、最初の試行はvoidパラメーターを使用します)。あなたの方法では、次のように定義します:

int *gnabber(){
  static int foo[] = {1,2,3}
  return foo;
}
2
Mark