C ++でどのように「再割り当て」しますか?


87

reallocC ++でどのようにできますか?それは言語から欠落しているようです-ありますがnewありdeleteませんresize

プログラムがより多くのデータを読み取るにつれて、それを保持するためにバッファーを再割り当てする必要があるため、これが必要です。delete古いポインタを使用してnew、新しい、より大きなポインタを使用することは正しい選択肢ではないと思います。


8
Stroustrup氏は見、長い時間戻ってこれを答え:www2.research.att.com/~bs/bs_faq2.html#renew(あなたはクラインのC ++よくある質問と一緒にC ++に新しいしている場合は良いスタートだこと。)
dirkgently

9
@dirkgentlyが参照する回答は、stroustrup.com / bs_faq2.html#renewにあります。また、ClineのFAQはスーパーFAQの一部になっています:isocpp.org/faq
maxschlepzig

回答:


54

:: std :: vectorを使用してください!

Type* t = (Type*)malloc(sizeof(Type)*n) 
memset(t, 0, sizeof(Type)*m)

になります

::std::vector<Type> t(n, 0);

次に

t = (Type*)realloc(t, sizeof(Type) * n2);

になります

t.resize(n2);

代わりにポインタを関数に渡したい場合

Foo(t)

使用する

Foo(&t[0])

ベクトルはスマートなC配列であるため、これは絶対に正しいC ++コードです。


1
memset行をmemset(t、0、sizeof(T)* n);にするべきではありませんか?mの代わりにn?
ラファエルメイヤー

1
@anthomはい。それは本当にあるべきですType* t = static_cast<Type*>(malloc(n * sizeof *t));
Ryan Haining

2
C ++ 11t.data()では、代わりに&t[0]
knedlsepp 2015年

1
どうすればこれを削除できますか?
a3mlord 2015年

@ a3mlord:どういう意味ですか?それを範囲外にしましょう、そしてそれはなくなっています。
軌道上でのライトネスレース2016年

50

正しいオプションは、おそらく、のようにあなたのために仕事をするコンテナを使用することですstd::vector

newまたdelete、指定されたタイプのオブジェクトを保持するのに十分なメモリを割り当てるため、サイズを変更できません。特定のタイプのサイズは変更されません。ありますがnew[]delete[]それらを使用する理由はほとんどありません。

どのようなreallocC言語でないことだけである可能性が高いmallocmemcpyfree利用できる十分な連続空きメモリがある場合、メモリマネージャは、巧妙な何かをするために許可されているものの、とにかく。


6
@bodacydo:拡大するバッファを実装せず、使用するだけstd::vectorです。必要に応じて自動的に拡大し、必要に応じてメモリを事前に割り当てることができます(reserve())。
シャープトゥース2010

4
std :: vector <T>を使用します。それが目的です。C ++では、リソース管理クラスを明示的に記述していない限り、new / delete / new [] / delete []を自分で使用する理由はまったくありません。
子犬

4
@bod:はい、できます。(std::stringちなみに、そうすることができます。)
fredoverflow 2010

1
はい、できます。問題ありません。それさえstd::stringできます。ちなみに、データの読み取りも簡単になる可能性があります。データをどのように読んでいますか?
トーマス

2
のようthevector.resize(previous_size + incoming_size)に聞こえ、その後にmemcpy(または同様の)が続くのは、&thevector[previous_size]必要なものです。ベクトルのデータは「配列のように」保存されることが保証されています。
トーマス

38

C ++でのサイズ変更は、コンストラクタとデストラクタを呼び出す必要がある可能性があるため、厄介です。

私はあなたが持っていることができなかった理由をC ++で根本的な理由がないと思うresize[]と行くためにオペレータnew[]delete[]これに似た何かをしました、:

newbuf = new Type[newsize];
std::copy_n(oldbuf, std::min(oldsize, newsize), newbuf);
delete[] oldbuf;
return newbuf;

明らかにoldsize、秘密の場所から取得されます。これは、delete[]にあるのと同じでTypeあり、オペランドの型から取得されます。resize[]タイプがコピーできない場合は失敗します-そのようなオブジェクトは単に再配置できないため、これは正しいです。最後に、上記のコードはデフォルトです-オブジェクトを割り当てる前にオブジェクトを構築しますが、実際の動作としては望ましくありません。

newsize <= oldsize新しく縮小された配列の「終わりを過ぎて」オブジェクトのデストラクタを呼び出し、他に何もしないという最適化の可能性があります。標準では、この最適化が必要か(resize()ベクトルの場合のように)、許可されているが指定されていないか、許可されているが実装に依存しているか、禁止されているかを定義する必要があります。

次に、自分自身に問いかける必要があります。「これを提供することは実際に有用であり、それvectorも可能であり、サイズ変更可能なコンテナ(連続メモリの-C ++ 98では要件が省略されていますが)を提供するように特別に設計されています。 C ++ 03で修正されました)これは、C ++の方法で配列を実行するよりも適していますか?」

答えは「ノー」だと広く考えられていると思います。サイズ変更可能なバッファをCの方法で実行するmalloc / free / realloc場合は、C ++で使用可能なを使用します。サイズ変更可能なバッファをC ++の方法で実行する場合は、ベクトルを使用します(またはdeque、実際に連続したストレージが必要ない場合は)。new[]ベクトルのようなコンテナを実装している場合を除いて、rawバッファにを使用して2つを混合しようとしないでください。


0

これは、reallocを使用して単純なベクトルを実装するstd :: moveの例です(制限に達するたびに* 2)。私が以下に持っているコピーよりもうまくやる方法があれば、plsは私に知らせます。

次のようにコンパイルします。

  g++ -std=c++2a -O2 -Wall -pedantic foo.cpp

コード:

#include <iostream>
#include <algorithm>

template<class T> class MyVector {
private:
    T *data;
    size_t maxlen;
    size_t currlen;
public:
    MyVector<T> () : data (nullptr), maxlen(0), currlen(0) { }
    MyVector<T> (int maxlen) : data (new T [maxlen]), maxlen(maxlen), currlen(0) { }

    MyVector<T> (const MyVector& o) {
        std::cout << "copy ctor called" << std::endl;
        data = new T [o.maxlen];
        maxlen = o.maxlen;
        currlen = o.currlen;
        std::copy(o.data, o.data + o.maxlen, data);
    }

    MyVector<T> (const MyVector<T>&& o) {
        std::cout << "move ctor called" << std::endl;
        data = o.data;
        maxlen = o.maxlen;
        currlen = o.currlen;
    }

    void push_back (const T& i) {
        if (currlen >= maxlen) {
            maxlen *= 2;
            auto newdata = new T [maxlen];
            std::copy(data, data + currlen, newdata);
            if (data) {
                delete[] data;
            }
            data = newdata;
        }
        data[currlen++] = i;
    }

    friend std::ostream& operator<<(std::ostream &os, const MyVector<T>& o) {
        auto s = o.data;
        auto e = o.data + o.currlen;;
        while (s < e) {
            os << "[" << *s << "]";
            s++;
        }
        return os;
    }
};

int main() {
    auto c = new MyVector<int>(1);
    c->push_back(10);
    c->push_back(11);
}

-7

そのようなことを試してください:

typedef struct Board
{
    string name;
    int size = 0;
};

typedef struct tagRDATA
{
    vector <Board> myBoards(255);

    // Board DataBoard[255];
    int SelectedBoard;

} RUNDATA;

ベクトルは文句を言うでしょう。そのため、arrays、malloc、newがまだ存在しています。


12
いいえ、それは理由ではありません。そして、これがどのように質問に答えるかはわかりません。または、なぜ使用しているのかtypedefあなたはC.書いたかのようにどこでも
軌道上での明度レースを
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.