48

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

int[] test(void); // ??
4

5 に答える 5

61

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
}

これはより簡単で安全です。

于 2010-11-24T07:18:16.800 に答える
19

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依存することができます。vectorarray

組み込みの配列を本当に使用したい場合(上記の標準ライブラリ クラスとは異なり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...
}
于 2010-11-24T07:37:45.917 に答える
9

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;
}
于 2010-11-24T07:47:28.993 に答える
2

関数から配列を返したい場合は、関数を終了すると値がなくなるため、値がスタックに格納されていないことを確認する必要があります。

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

int *gnabber(){
  static int foo[] = {1,2,3}
  return foo;
}
于 2010-11-24T07:27:58.750 に答える
-1

「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;
于 2015-03-04T11:30:01.453 に答える