2

それまで私は対処していましたが、ここではベクトルを使用して独自のコンテナクラスを構築しようとしています。仕事に必要です。コードブロック10.05を使用しています

class myclass
{
    public :
      vector<myclass> array;
      char * classname;
      ...

問題は、デストラクタで削除が行われない場合、クラスのデータが画面に適切に表示されることです。クラス名を削除すると、関数show()は奇数文字を表示します。私はそれがオブジェクトを構築するための私のメソッドから来ていると思います、そして私がそれらを引数として渡すときの範囲の問題。

 myclass::~myclass()
 {
    //if(classname) delete [] classname;
 }

そして、これはコンストラクターで初期化される方法です:

 myclass::myclass(long lvl = 0, const char name[] = "undefined")
    :ID(++ ID_counter)
    {
       level = lvl;

       int namelength = strlen(name);
       classname = new char[namelength + 1];
       strcpy(classname, name);
    }

add_content(const myclass&c)は、c.arrayの要素のコピーを作成し、これらをth​​is-> arrayに「push_back」することになっています。パラメーターとして名前のないオブジェクトを配置できる可能性があります:mycontainer.add_content (myclass(3,5)); それは動作しますが、私はそれが持つべき範囲について懐疑的です

> int main()
>     {
>        myclass mycontainer(0);
>        mycontainer.add_content(myclass(3,5));
>     ...

これが完全なコードです:

#include <vector>
#include <iostream>
using namespace std;

class myclass
{
  public :

   vector<myclass> array;
   static long ID_counter;
   long ID;
   long level;
   char * classname;

   myclass(int n, long lvl, const char name[]); //push_back n elements, lvl = 0, name = "undefined"
   myclass(long lvl, const char name[]); //lvl = 0, name = "undefined"
   myclass::~myclass();

   void set_level(long lvl); //recursive function, go down the tree
   void add(int n); //push_back n elements
   void add(const myclass & c); //push_back and set back the levels
   void add_content(const myclass & c); //push_back all the c.array[i] and set back the levels

   void show();

   template <typename T> myclass & operator[](const T it){ return array[it]; }
};

long myclass::ID_counter = 0;

myclass::myclass(long lvl = 0, const char name[] = "undefined")
:ID(++ ID_counter)
{
   level = lvl;

   int namelength = strlen(name);
   classname = new char[namelength + 1];
   strcpy(classname, name);
}
myclass::myclass(int n, long lvl, const char name[] = "undefined")
:ID(++ ID_counter)
{
   level = lvl;

   int namelength = strlen(name);
   classname = new char[namelength + 1];
   strcpy(classname, name);

   for(int i = 0; i < n; i++) array.push_back( myclass(this->level + 1) );
}
myclass::~myclass()
{
   //if(classname) delete [] classname; //there is the point !
}

void myclass::add(int n = 1)
{
   for(int i = 0; i < n; i++) array.push_back( myclass(level + 1) );
}

void myclass::add(const myclass & c)
{
   array.push_back(c);
   array[array.size() - 1].set_level(level + 1);
}

void myclass::add_content(const myclass & c)
{
   for(int i = 0; i < c.array.size(); i++)
   {
      array.push_back(c.array[i]);
      array[array.size() - 1].set_level(level + 1);
   }
}

void myclass::set_level(long lvl)
{
   level = lvl;
   for(int i = 0; i < array.size(); i++) array[i].set_level(level + 1);
}

void myclass::show()
{
   cout << "ID : " << ID << "\tLvl : " << level << "\t Classname : " << classname << endl;
}

int main()
{
   myclass mycontainer(0); //ground level
   mycontainer.add_content(myclass(3,5)); //the 3 elements level 5 should be reset to 0+1

   mycontainer.show();

   for(int i = 0; i < mycontainer.array.size(); i++)
   {
      mycontainer[i].show();

      for(int j= 0; j < mycontainer[i].array.size(); j++)
         mycontainer[i][j].show();
   }
   cout << "\ncheckpoint\n";
   system("PAUSE"); //press any key to crash!
   return 0;
}

ここでは、デストラクタの* classnameは削除されません。プログラムは、これをレンダリングします。

ID : 1  Lvl : 0  Classname : undefined
ID : 3  Lvl : 1  Classname : undefined
ID : 4  Lvl : 1  Classname : undefined
ID : 5  Lvl : 1  Classname : undefined

checkpoint
Appuyez sur une touche pour continuer...

削除すると、いくつかの悪い文字がクラッシュして表示されます:

ID : 1  Lvl : 0  Classname : undefined
ID : 3  Lvl : 1  Classname : ░(?
ID : 4  Lvl : 1  Classname : ░(?
ID : 5  Lvl : 1  Classname : ░(?

checkpoint
Appuyez sur une touche pour continuer...

Process returned -1073741819 (0xC0000005)   execution time : 29.651 s
Press any key to continue.

私は引数とポインタに関するいくつかの原則を研究しようとしましたが、この言語は経験的すぎて意味がありません。助けてくれてありがとう。

4

2 に答える 2

7

生のポインターがあり、コピーコンストラクターまたは代入演算子を定義していません。つまり、自動生成されたバージョンを取得しているということです。三つのルールを確認します。

解決策1:適切なコピーコンストラクターと代入演算子を実装します。

解決策2:に変更char * classnamestd::string classnameます。これで、自動生成されたコピーコンストラクタと代入演算子が機能します。追加の利点:を使用する必要はnewありません。を使用する必要はありませんdelete

于 2012-12-19T19:42:26.647 に答える
1

コピーコンストラクターを定義する必要があります。

私のデバッガーはここでエラーを発生させます:

for(int i = 0; i < n; i++) array.push_back( myclass(this->level + 1) );

ここでは、の新しいオブジェクトmyclassが作成され、にコピー(複製)されてarrayから、他のローカル変数と同じように元のオブジェクトが破棄されていることがわかります。

したがって、同じポインタを持つ2つのインスタンスがあります。1つは破棄され、もう1つは内部arrayにあり、rawメモリのみをコピーするデフォルトのコピーコンストラクタによって作成されます。したがって、デストラクタがすでに実行されているため、内部のインスタンスarrayは無効です。

コード

次の追加のコンストラクターが状況を解決します。

myclass::myclass(const myclass& other) 
:ID(++ ID_counter) 
{
   level = other.level;

   int namelength = strlen(other.classname);
   classname = new char[namelength + 1];
   strcpy(classname, other.classname);
}

(上記は「コピーコンストラクター」と呼ばれるものです。もちろん、すべての潜在的なバグを回避するために「三つのルール」に従う必要があります)

于 2012-12-19T19:48:16.547 に答える