3

私はまだ C++ の経験が浅いので、これが基本的なことである場合はご容赦ください。

以下のようなコードがあります。Lは抽象クラス (多数の純粋仮想関数を持つ) でありA、 、BおよびCはすべて から派生した通常のクラスLです。これらはいくつあっても構いませんが、それらはすべて異なります。

int main() {
    // ...

    std::vector<L*> ls(3) ; 

    ls[0] = new A ;
    ls[1] = new B ;
    ls[2] = new C ;

    int i ;
    for (i = 0 ; i < ls.size() ; i++) {
        if (ls[i]->h()) {
            // ...
        }
    }

    // ...
}

それは機能しますが、そのベクトルを初期化するためのより良い方法が本当に必要です。右?

ベクトルは、最初に初期化された後に変更されることは想定されていません。ただし、さまざまなオブジェクト自体が内部で変更される可能性があるため、const にすることはできないと思います。通常の配列よりもベクトルを選択したのは、その長さを手動で追跡したくないためです (エラーが発生しやすいことが判明しました)。

main理想的には、ベクトルの定義と初期化を別のファイルから取り出し、できれば別のファイルに取り出したいと思います#include。私が試してみると、コンパイラは「「=」トークンの前にコンストラクタ、デストラクタ、または型変換が必要である」と不平を言います。すべてのクラスAには、BデフォルトのCコンストラクターがあります。

deleteまた、 を使用して作成したものはすべて手動で作成する必要があるという印象を受けましたが、またはのいずれでもnew削除されません。試してみると、コンパイラは「type 'class std::vector<L*, std::allocator<L*> >' argument given to 'delete', expected pointer」と不平を言います。lsdeletedelete[]delete ls;

上記は安全ですか、それともメモリの問題を引き起こしますか?

4

4 に答える 4

4

しかし、そのベクトルを初期化するためのより良い方法が本当に必要です。右?

少なくとも C++0x がなければ、そうは思いません。あなたはどちらの方法を好みますか?初期化コードはまったく問題ありません。

ただし、さまざまなオブジェクト自体が内部で変更される可能性があるため、const にすることはできないと思います。

ベクトル自体を作成することはできますがconst、そのメンバ型のみをポインタにすることはできませんconst

通常の配列よりもベクトルを選択したのは、その長さを手動で追跡したくないためです (エラーが発生しやすいことが判明しました)。

定数配列の長さを追跡する必要はありません。

L* ls[] = { new A, new B, new C };
// with <boost/range/size.hpp>
std::size_t num = boost::size(ls);
// without Boost, more error-prone
// std::size_t num = sizeof ls / sizeof ls[0];

また、Boost.Range などのように、サイズを指定する必要がないこともよくあります。

理想的には、ベクトルの定義と初期化をメインから引き出し、できれば別のファイルに入れ、#include できるようにしたいと考えています。

これは、1 つの定義のルールに違反します。宣言はヘッダー ファイルに入れることができますが、定義はソース ファイルに入れる必要があります。

また、new を使用して作成したものはすべて手動で削除する必要があるという印象を受けましたが、delete または delete[] を使用しても ls は削除されません。

あなたの印象は正しいですが、 で作成したのではなく、その要素lsのみを作成しました。ベクトルを使用した後、ベクトル自体ではなく、その各要素を使用する必要があります。newdelete

ポリモーフィック ポインターを保持する STL コンテナーの代替として推奨されるのは、Boost ポインター コンテナー ライブラリです。

于 2011-05-09T18:28:55.657 に答える
1

実際、作成したオブジェクトに対して削除を使用する必要があります。オブジェクトではなくベクトルで削除を呼び出しています。何かのようなもの:

for(size_t i = 0; i < ls.size(); i++){
    delete ls[i];
}

構築の問題については、それらを関数にラップし、その関数を独自のヘッダー ファイルに入れることができます。関連するすべてのクラス ヘッダー ファイルも含める必要があります。

void init_vector(std::vector<LS*> & v){
    ls[0] = new A ; 
    ls[1] = new B ;
    ls[2] = new C ;
}
于 2011-05-09T18:22:05.350 に答える
0

std::arrayC ++ 11が許容できる場合は、次の代わりに使用する方がよい場合がありますstd::vector

std::array<L *, 3> = {new A(), new B(), new C()};
于 2011-05-09T18:46:18.860 に答える
0

コンパイル時にサイズがわかるので、 のarray代わりに を使用することをお勧めしvectorます。arrayC スタイルの配列の代わりにクラス テンプレートを使用すると、 vector. つまりsize()、配列を呼び出してイテレータなどを取得できます。

オブジェクトを忘れないようにするためにdelete、スマート ポインターを使用することをお勧めします。

#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

boost::array<boost::shared_ptr<L>, 3> ls = { {
    boost::make_shared<A>(),
    boost::make_shared<B>(),
    boost::make_shared<C>(),
} };

最新のコンパイラは、独自のバージョンのarrayshared_ptrを標準ライブラリに同梱しています。

#include <array>
#include <memory>

std::array<std::shared_ptr<L>, 3> ls = { {
    std::make_shared<A>(),
    std::make_shared<B>(),
    std::make_shared<C>(),
} };

最も外側の中かっこは技術的には必要ありませんが、それらを省略するとコンパイラの警告が生成される可能性があることに注意してください。少なくとも私のコンパイラではそうです。

理想的には、ベクトルの定義と初期化を別のファイルから引き出し、mainできれば別のファイルに入れたいと思います。#include

その場合、宣言を含むヘッダー ファイルと、次の定義を含む実装ファイルが必要ですls

// file ls.h

#ifndef LS_H
#define LS_H

#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>

extern boost::array<boost::shared_ptr<L>, 3> ls;

#endif

// file ls.cpp

#include "ls.h"
#include <boost/make_shared.hpp>

boost::array<boost::shared_ptr<L>, 3> ls = { {
    boost::make_shared<A>(),
    boost::make_shared<B>(),
    boost::make_shared<C>(),
} };
于 2011-05-09T18:50:51.670 に答える