• ベストアンサー

C++でUNDOを実装しようとしています。

C++でUNDOを実装しようとしています。 処理前にクラスオブジェクトをコピーしておき、 UNDOの処理では処理前のクラスを元のクラスに かぶせてしまえば処理前の状態に戻ると思うの です。 ところが、クラスオブジェクトの中でポインタ 変数があり、コピーした内容も書き換わってし まいます。 いわゆるディープコピーをしなければならない らしいということまで分かったのですが、その 方法がわかりません。 サンプルなどが掲載されているホームページが ありましたら、そのURLを教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

 続きです。 void test() { std::list<CObject> l; CObject a(3, "CObject - 1"); for(std::size_t n = 0; n < a.size(); ++n) a[n] = CPoint(n, n); ::Print(a); std::cout << a.GetName() << "を退避" << std::endl; l.push_back(a); a = CObject(5, "CObject - 2"); for(std::size_t n = 0; n < a.size(); ++n) a[n] = a[n] + CPoint(n + 2, n + 1); ::Print(a); std::cout << a.GetName() << "を退避" << std::endl; l.push_back(a); a = l.front(); std::cout << a.GetName() << "を復元" << std::endl; ::Print(a); } int main() { ::test(); //VC++特有 //const int result = ::_CrtDumpMemoryLeaks(); return 0; }

furuhashi-its
質問者

補足

回答ありがとうございます。 掲載いただいたソースを参考に頑張ってみます。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

  • rabbit_cat
  • ベストアンサー率40% (829/2062)
回答No.4

ディープコピーの話ではないですが。 UNDO/REDOを実装するのは、 処理対象のクラス自体を時系列にそって全て覚えておく でも、まあいいといえばいいですが これだと、ものすごくメモリを食います。 普通は、そうではなくて、 処理対象のクラスのインスタンス自体を覚えておくのではなくて、 なんらかの処理そのものを表わすクラス(コマンドクラス)を作って、 これを覚えておきます。UNDOしたいときには、現在の処理対象のクラスに対して、処理を逆に適用します。 つまり、処理対象のクラスの時系列自体を覚えておくのではなくて、その差分だけをおぼえておくというか。 で、プログラムを組んでいると、こういうことをしたくなることはよくあるんで、 デザインパタンという形でまとめられています。 Commandパタンと呼ばれています。 http://www.google.com/search?hl=ja&q=command%E3%83%91%E3%82%BF%E3%83%B3+UNDO+REDO

furuhashi-its
質問者

補足

回答ありがとうございます。 CommandパターンのUndo/Redoについて検討しましたが、 元々のコーディングがまったくその辺のことを考慮して いない為、今回は適用を断念しました。

全文を見る
すると、全ての回答が全文表示されます。
回答No.2

 こんばんは。  そのポインタがバッファを割り当てた物であればSTLのvector辺りで代用すれば、悩む必要もなくなるのでは。  以下はディープコピーです。コピーコンストラクタで処理をします。参考程度で。 #include<stdexcept> #include<iostream> #include<string> #include<list> #include<algorithm> struct CPoint { explicit CPoint(int x = 0, int y = 0) : x(x), y(y){ } int x; int y; }; const CPoint operator + (const CPoint& l, const CPoint& r) { return CPoint(l.x + r.x, l.y + r.y); } struct CObject { explicit CObject(std::size_t size = 1, const std::string& name = std::string("CObject")) : m_name(name), m_size(std::max(1U, std::min(size, 256U))), m_ppt(new CPoint[m_size]) { } CObject(const CObject& r) : m_name(r.m_name), m_size(r.m_size) { //ココがディープコピー this->m_ppt = new CPoint[this->m_size]; std::copy(r.begin(), r.end(), this->begin()); } CObject& operator = (const CObject& r) { if(&r == this)return *this; this->~CObject(); new (this) CObject(r); return *this; } ~CObject() { if(this->m_ppt == NULL)return; delete this->m_ppt; this->m_ppt = NULL; } void SetName(const std::string& name){ this->m_name = name; } const std::string GetName() const { return this->m_name; } std::size_t size() const { return this->m_size; } CPoint* begin(){ return this->m_ppt; } CPoint* end(){ return this->m_ppt + this->m_size; } const CPoint* begin() const { return this->m_ppt; } const CPoint* end() const { return this->m_ppt + this->m_size; } CPoint& operator [](std::size_t n) { return const_cast<CPoint&>(static_cast<const CObject&>(*this)[n]); } const CPoint& operator[](std::size_t n) const { if(n >= this->m_size)throw std::range_error("error"); return this->m_ppt[n]; } private: std::size_t m_size; CPoint* m_ppt; std::string m_name; }; void PrintPoint(const CPoint& p) { std::cout << "[x : " << p.x << "][y : " << p.y << "]" << std::endl; } void Print(const CObject& a) { std::cout << a.GetName() << "を表示" << std::endl; std::for_each(a.begin(), a.end(), &::PrintPoint); }

全文を見る
すると、全ての回答が全文表示されます。
  • t_nojiri
  • ベストアンサー率28% (595/2071)
回答No.1

クラス構造がどうなってるか分かりませんが、可変長の文字列が有るなら、ポインタの先とかを何処かメモリ上にコピー展開しておくとか、ストリングスオブジェクトをコピーしておかないといけませんよね。 単純では無いと思いますけど、UNDOするストリングスオブジェクト毎に設計する方が良いんじゃないですか? http://www.geocities.jp/naosacra/mops/Manual/III_2/strings.html

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • ◆コピコンを実装しないと、returnでエラー?

    ポインタを持ったクラスで、 コピーコンストラクタを実装していないと、 newを使用した際にエラーになるそうですが、 なぜなのでしょうか? 値渡しの関数などで、 コピーコンストラクタを実装していないと、 デフォルトコピーコンストラクタで、ポインタ型のメンバ変数の値もコピーするため、 return する前に、 「一時的な変数としてコピーされていた値渡しの引数」が、 関数の終了時に解放され、 「アドレスを指しているポインタ」が指し示す先の領域に「delete」が走ってしまうため、 呼び元の変数で持っているポインタが指し示す先の領域も、 解放されてしまうとかでしょうか?? そもそも、 ポインタ pMem=NULL は、アドレスの指し示す値のリセットで、 Delete pMem は、アドレスが指し示す先頭から、そのクラスで必要としている分のメモリ量進んだアドレスまでを、解放する。 ということで合っているでしょうか? それとも、 「ポインタ」を削除しても、ポインタの指し示す先のアドレス自体は存在していて、 「呼び元」のアドレス格納用領域と、 「関数の呼び出し時にコピーコンストラクタで作られるアドレス格納用領域」は別であり、 ポインタ自体を削除しても、ポインタの先にあるメモリ領域は残っているのでしょうか?

  • c# Undo/Redo 関係

     こんにちは。c#初心者です。  Undo/Redo機能を実装しようとしていて気になることがあったので質問です。  最初はよくわからなかったので、とりあえず何も見ずに、思いつきでIUndoer, IRedoerを用意してポリモーフィズム全開でやろうとしていました(ちゃんと何か読めよ)。 public interface IUndoer {   /// <summary>1つ前の状態に戻し、Redoerを生成します。</summary>   /// <returns>Redoer</returns>   IRedoer Undo(); } public interface IRedoer {   /// <summary>1つ次の状態に戻し、Undoerを生成します。</summary>   /// <returns>Undoer</returns>   IUndoer Redo(); } class TextChangeUndoer : IUndoer { // 略 } class TextChangeRedoer : IRedoer { // 略 } class PointChangeUndoer : IUndoer { // 略 } class PointChangeRedoer : IRedoer { // 略 } ・ ・  こんな感じで、とりあえずStack<T>に放り込んでやる予定でした。が、途中でよく考えてみれば、対応するUndoerとRedoerは中身が同じだったことに気づきました(遅っ)。  という訳で、上のクラスたちは class TextChanger : IUndoer, IRedoer { // 略 } class PointChanger : IUndoer, IRedoer { // 略 } ・ ・  こんな感じになりました。ここでクエスチョンです。  一旦は1つにまとめましたが、 A、「UndoとRedoで概念が違うため、元通りに2つのクラスに分けるべき」 B、「そもそもIUndoerとか、IRedoerとか分ける必要がない(端的に言えばIUnRedoerみたいなのでいい)」 C、「今のが良い」 D、「興味ないね」 E、「その前に何か読め」 Z、「その他」  のいずれが好ましいでしょうか? 皆さんのご意見を伺わせてください。

  • 『オブジェクト化』の実装例が よく分からない

    『オブジェクト化』の実装例が よく分からない 保守性を高めるために オブジェクト化を進めることが大切なのは 雰囲気的に分かります。 ところが、実際に何をすればよいか、という段階になると 具体策が見えてきません。 以前に、下記の回答が出されていましたが 意味が良く分からないで困っています。 ========== 過去の回答 ======== http://okwave.jp/qa/q8601972.html ・マジックナンバー、マジックストリングを排除する オブジェクト内に定数プロパティとしてまとめ ・処理のメソッド化 「変数・定数をすべて1つのオブジェクトにまとめる」 「処理はオブジェクトのメソッドにまとめる」 更に、定義したオブジェクト類は別ファイルに切り離し、 そのスクリプトファイルをロードするようにすれば、 ページデザインと処理(ビジネスロジック)も切り離し別々に管理できます。 ========================= これより分かりやすい実例を教えていただけますでしょうか。 ありがとうございます。

  • Strategyパターンを用いた実装について

    Strategyパターンを用いた実装について 現在Javaを勉強しており、 Strategyパターンを用いた以下の実装を考えています。 public class UseStrategy { private Strategy strategy; public void doSomthing(int num) { switch (num) { case 0: strategy = new AlphaStrategy(); break; case 1: strategy = new BetaStrategy(); break; case 2: strategy = new GammaStrategy(); break; } // 変数strategyを用いて処理を続行していく // ... } private interface Strategy { public abstract void method_1(); public abstract void method_2(); } private class AlphaStrategy implements Strategy { @Override public void method_1() { //do something } @Override public void method_2() { //do something } } private class BetaStrategy implements Strategy { @Override public void method_1() { //do something } @Override public void method_2() { //do something } } private class GammaStrategy implements Strategy { @Override public void method_1() { //do something } @Override public void method_2() { //do something } } } つきましては、以下ご質問させてください。 (1)Strategyパターンの実装において、  上記UseStrayegyクラスのように、あるクラスの入れ子クラスとして  Strategyインターフェース及び、その実装クラスを実装する方法は  普通でしょうか?    それとも、入れ子クラスとしてではなく、Strategyインターフェース、  その実装クラスを全て 別クラスファイルに分けた方が良いのでしょうか? (2)例として、  BetaStrategy.method_2()とGammaStrategy.method_2()の処理が全く  同じだったとします。その場合、共通となる処理を一つのメソッド化し、  そのメソッドをBetaStrategy.method_2()とGammaStrategy.method_2()から  コールしたいと考えております。  その際、共通となる処理メソッドの実装箇所としては、以下のいずれが良いのでしょうか。   (A)Strategyインターフェースを抽象クラス化し、二つの共通処理メソッドを実装する。  (B)UseStrategyクラスに、共通処理を実装する。    それとも、上記の様なケースがある場合Strategyパターンは不適切でしょうか。 文面に分かりづらい面や、Javaのオブジェクト指向・デザインパターンについて 理解の乏しいところがあるかと思いますが、ご回答の程よろしくお願いいたします。

    • ベストアンサー
    • Java
  • ATL CWorkerThread

    初歩的な質問で申し訳ないですが、ATLにおけるCWorkerThreadを使ってマルチスレッドプログラミングをしたいのですが、情報が少なく、msdnを見てもサンプルが無いようなので利用法がいまいちわかりません。 どなたか簡単なサンプルでもよいので教えていただけないでしょうか。 具体的には、以下の解説 http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/vclib/html/vclrfcworkerthread.asp ----------------------------------------- CWorkerThread クラスを使用するには 1. このクラスのインスタンスを作成します。 2. CWorkerThread::Initialize を呼び出します。 3. CWorkerThread::AddHandle を、カーネル オブジェクトのハンドルと、IWorkerThreadClient の実装へのポインタを指定して呼び出します。 または CWorkerThread::AddTimer を IWorkerThreadClient の実装へのポインタを指定して呼び出します。 4. IWorkerThreadClient::Execute を実装し、ハンドルまたはタイマがシグナルを送信したときにアクションを実行します。 5. CWorkerThread::RemoveHandle を呼び出して、待機可能オブジェクトのリストからオブジェクトを削除します。 6. CWorkerThread::Shutdown を呼び出して、スレッドを終了します。 ------------------------ の3の、カーネル オブジェクトのハンドルが何かがよくわかりません。AddHandleに何のHANDLEを渡せばよいかで躓いています。

  • オブジェクト指向の実装方法

    オブジェクト指向では、クラス間の関係に「依存」「関連」「集約(composite/aggrigate)」などがありますが、実装上はどのように表現できるのでしょうか? たとえば、C++の場合は関連と集約を実装上区別することが(自分の知識では)できません。compositeとaggrigateは実体化ポインタかで区別しています。 Javaの場合はcompositeとaggrigateの区別もできない???(Javaはあまり詳しくありません。。。) C++、Java、その他、言語は何でも結構ですので、どのように表現しているか教えてください。

  • blowfishの実装について

    はじめまして! 現在暗号化アルゴリズムであるblowfishを実装しようと試みている最中なのですが、いまいちうまくいきません。 http://www.di-mgt.com.au/crypto.html 上記のページにあるフリーのサンプルを利用し、 ・任意の文字列を暗号化してファイルに吐き出し ・ファイルから暗号化した文字列を取り出して複合化 という処理をしようとしているのですが、複合化がうまくいきません。 暗号化はサンプルアプリと同じ結果になるのでうまくいっているようです。 サンプルは暗号化した文字列変数をそのまま複合化しているのですが、そこにポイントがありそうなことまではわかりました。 処理単位が8ビットらしいのですが、当方、いかんせん英語がからっきしダメなことと、VB自体にそれほど精通していないので全く先に進みません。 どなたかご教授いただけないでしょうか? VBのサンプルや日本語での解説のあるサイト、書籍の紹介などでも結構です。 よろしくお願い致します。

  • C++の文法で分からないことがあります

    C++のコードを解析しているときに分からない部分が出てきたので教えていただきたいのですが... あるクラスのメンバ関数の引数で( {オブジェクト名}*& {変数名} )とあったのですが, *& てなんでしょうか? 参照へのポインタという意味かなとは思うのですがそれはそれで意味が分からないし、これを使うことでどんなことが起こるのか分かりません。 どなたか知っている方教えてください。 あと、objective-c++のリファレンスって存在するのでしょうか?あったらどこにあるのか教えてくださると非常に助かります。 よろしくお願いします。

    • 締切済み
    • Mac
  • サブクラス型オブジェクトをスーパークラス方に代入

    ある所で下記のような継承についての記述をみつけました。 ----------------------------------------------------------------------------- 継承の目的は、あるクラスで実装したメソッドなどの機能を利用して、 さらに実装を追加する差分コーディングです。 一つのクラスから複数のサブクラスを作ることも良くあります。 このような時、それらのサブクラス型オブジェクトの参照を代入できる変数として、 スーパークラス型変数を使うことがしばしばあります。 ----------------------------------------------------------------------------- サブクラス型オブジェクトの参照を代入できる変数として、 スーパークラス型変数を使うことがある、と いうのはどういった場合に使うのでしょうか。 よろしくお願いします。

    • ベストアンサー
    • Java
  • 別プロセスの起動

    別プロセスの起動について質問があります。 Java、Servlet、JSPを使って検索画面、検索処理を作っています。 レコード件数が何万件もあるので、検索処理を別プロセス(別クラス)で実行したいと考えています。 クラス構成は、 1.検索条件受け取りクラス 2.検索処理クラス 検索条件受け取りクラスで、検索条件をオブジェクトにし、そのオブジェクトを検索処理クラスの引数に渡し、別プロセスとして実行するような感じで考えています。 ※スレッドでの実装は、メモリを消費するため考えておりません。 実装方法やサンプルをよろしくお願いします。