2
/** @file ListP.cpp
 *  ADT list - Pointer-based implementation. */

#include <iostream>
#include <cstddef>  // for NULL
#include <new>   // for bad_alloc
#include "ListP.h"  // header file

using namespace std;

List::List() : size(0), head(NULL)
{
} // end default constructor

List::List(const List& aList) : size(aList.size)
{
 if (aList.head == NULL)
  head = NULL; // original list is empty

 else
 { // copy first node
  head = new ListNode;
  head->item = aList.head->item;

  // copy rest of list
  ListNode *newPtr = head; // new pointer
  // newPtr points to last node in new list
  // origPtr points to nodes in original list
  for (ListNode *origPtr = aList.head->next; origPtr != NULL; origPtr = origPtr->next)
  { 
   newPtr->next = new ListNode;
   newPtr = newPtr->next;
   newPtr->item = origPtr->item;
  } // end for

  newPtr->next = NULL;
 } // end if
} // end copy constructor

void List::copy(const List& aList)
{
 List::List(aList);
} // end copy

単にコピーコンストラクターを呼び出すcopyというメソッドを作成しようとしています。このメソッドをメインでテストすると、ターゲットリストはまだ空のままです。私はそれをステップスルーし、すべての正しい行が実行されましたが、コピーコンストラクターが戻ったときに何も保存されていないようです。これはスコープと関係があると思いますが、問題を特定することはできません。ドライバープログラムは次のとおりです。

#include <iostream>
using namespace std;

#include "ListP.h" 

int main ()
{
 List aList;

 ListItemType dataItem;
 aList.insert(1, 9);    
 aList.insert(2, 4); 
 aList.insert(3, 1); 
 aList.insert(4, 2); 

 List bList;
 bList.copy(aList);

 bList.retrieve(1, dataItem);
 cout << dataItem << endl;
 cout << bList.getLength() << endl;

 return 0;
}
4

4 に答える 4

4

私があなたの質問を理解しているなら、あなたはあなたがやろうとしていることをすることができません.

オブジェクトで他のメソッドを呼び出す前に、オブジェクトが完全に構築されている必要があります (ここには例外があります。それについては後で説明します)。さらに、オブジェクトは 1 回しか構築できません (*)。したがって、コピー メソッドを呼び出すことができるまでに、オブジェクトは既に構築されており、2 度目に構築することはできません (また、構築すべきではありません)。

完全に構築されていない (つまり、コンストラクターがまだ返されていない) オブジェクトでメソッドを呼び出すことができない唯一の例外は、コンストラクター自体が部分的に構築されたオブジェクトでメソッドを呼び出すことができることです。したがって、コピー コンストラクターからコピー メソッドを呼び出すことはできますが、その逆はできません。

そうは言っても、オブジェクトが最適化されたスワップ関数を提供する場合、次のことを考える標準的なトリックがあります。

void List::copy(const List& aList)
{
    List acopy(aList);
    swap(*this, acopy);
}

これにより、aList のコピーが作成され、オブジェクトの現在の内容がこのコピーと交換されます。以前のリストの内容を持つコピーは、コピーが戻ったときに適切に破棄されます。

最後に、それを行う場合、現在の推奨事項は、実際には少し調整して、次のように記述することです。

void List::copy(List aList)
{
    swap(*this, aList);
}

特定の状況下では、これがより効率的になります (効率が低下することはありません)。

* - 変なことをして、placement new でオブジェクトを 2 回作成できます。しかし、それを行う正当な理由はなく、そうしない理由はたくさんあります。

于 2010-01-09T07:56:24.153 に答える
2

あなたのドライバープログラムでは、

List bList;
bList.copy(aList);

代わりに、コピー コンストラクターを次のいずれかで呼び出します。

List bList(aList);

また

List bList = aList;

…「コピー」メソッドを見ると、コンストラクターが新しいインスタンスを作成します。List::copy メソッドはコピー コンストラクターを呼び出し、スタックに List の新しいインスタンスを作成します。その後、戻り、新しいインスタンスはなくなります。

「コピー」メソッドの代わりにおそらく必要なのは、代入演算子を定義することです。

List& List::operator=(const List& aList)
{
   if (this != &aList)
   {
      // Do your copying here
   }

   return *this;
}

次に、ドライバーは次のように言うことができます

List bList;
// ...Presumably manipulate bList in some other ways in-between...
bList = aList;

同じクラスの別のメソッド内から代入演算子を呼び出すには、次のようにします。

*this = aList;

また

operator=(aList);

後者はむずかしいと思います。ただし、メンバー関数へのポインターを取得する場合は、名前で明示的に演算子を参照する必要があります。

于 2010-01-09T07:19:08.910 に答える
2

コンストラクターは、オブジェクトが初期化されていない場合にのみ呼び出されるため、特別です。したがって、コピーなどの単純な関数として呼び出すことはできません。C++ はこれを必要とします。これは、機能を追加するときに壊れにくいコードを作成するのに役立つためです。

おそらくあなたが望むのは、コピー コンストラクターの本体を に移動してからCopy()呼び出すことです。Copy()List::List(List const&)

于 2010-01-09T07:59:03.560 に答える
1

問題は、そのような構文が非常に簡単な場合、なぜcopyメソッドを作成するのかということです:> (明示的に記述されたコピーを必要とする防御的な人々の1人でない限り、私は提出します、私も彼らの1人です)。

代わりにコピー (代入)演算子を使用することにも興味があるかもしれません。

List& List::operator=(const List& aList)
{
    //
}

コピー コンストラクターを呼び出せないことについては、C++ FAQ Lite on Constructorsを参照してください。このスレッドも同じ質問をします。

クラスから明示的にコンストラクターを呼び出すことができないことは、C++ 標準ドキュメントの一部ですが、まあ、そのことを読みたくない... まだ ;-)

于 2010-01-09T07:12:07.727 に答える