0

コピーコンストラクターと代入演算子を実装して、クラスに対してこれらを再定義するときにわずかな変更だけが必要になるようにする方法があるかどうか疑問に思っています。

たとえば、クラスを次のように考えます。

class Foo {
private:
    int* mInt_ptr;
    /* many other member variables
       of different types that aren't
       pointers */
public:
    Foo();
    Foo(const Foo&);
    Foo& operator=(const Foo&);
    ~Foo();
};

ここで、ポインターmInt_ptrを処理するには、コピーコンストラクターと代入演算子で適切に処理する必要があります。ただし、残りのメンバー変数は、の浅いコピーを実行しても安全です。これを自動的に行う方法はありますか?

クラスが大きくなると、非ポインターメンバー変数をコピーする操作を明示的に書き出すのは面倒で扱いにくくなる可能性があるため、たとえば、次のようなコピーコンストラクターを作成する方法があるかどうか疑問に思います。

Foo::Foo(const Foo& tocopy)
{
    mInt_ptr = new int(*tocopy.mInt_ptr);
    /* Do shallow copy here somehow? */
}

明示的な形式ではなく:

Foo::Foo(const Foo& tocopy)
{
    mInt_ptr = new int(*tocopy.mInt_ptr);
    mVar1 = tocopy.mVar1;
    mVar2 = tocopy.mVar2;
    ...
    ...
    mVarN = tocopy.mVarN;
}
4

3 に答える 3

4

一般的に、あなたが今戦っているまさにその理由のために、生のポインタを使用しないでください。代わりに、適切なスマートポインターを使用し、コピーとスワップの割り当てを使用します。

class Foo
{
     int a;
     Zip z;
     std::string name;
     value_ptr<Bar> p;

public:
     Foo(Foo const &) = default;

     Foo & operator=(Foo rhs)
     {
         rhs.swap(*this);
         return *this;
     }

     void swap(Foo & rhs)
     {
         using std::swap;
         swap(a, rhs.a);
         swap(z, rhs.z);
         swap(name, rhs.name);
         swap(p, rhs.p);
     }
};

namespace std { template <> void swap<Foo>(Foo & a, Foo & b) { a.swap(b); } }

value_ptr本格的な実装、または次のような単純なものである可能性があります。

template <typename T>    // suitable for small children,
class value_ptr          // but not polymorphic base classes.
{
    T * ptr;

public:
    constexpr value_ptr() : ptr(nullptr) { }
    value_ptr(T * p) noexcept : ptr(p) { }
    value_ptr(value_ptr const & rhs) : ptr(::new T(*rhs.ptr)) { }
    ~value_ptr() { delete ptr; }
    value_ptr & operator=(value_ptr rhs) { rhs.swap(*this); return *this; }
    void swap(value_ptr & rhs) { std::swap(ptr, rhs.ptr); }

    T & operator*() { return *ptr; }
    T * operator->() { return ptr; }
};
于 2012-09-05T17:06:55.643 に答える
2

すべてのシャローコピービットを小さなヘルパー構造体でラップし、そこでデフォルトのコピー動作を使用するのはどうですか。

class Foo {
private:
    int* mInt_ptr;
    struct helper_t
    /* many other member variables
       of different types that aren't
       pointers */
    } mHelper;
public:
    Foo();
    Foo(const Foo&);
    Foo& operator=(const Foo&);
    ~Foo();
};

Foo::Foo(const Foo& tocopy)
{
    mInt_ptr = new int(*tocopy.mInt_ptr);
    mHelper = tocopy.mHelper;
}

Kerrekが示唆したように、より優れたプリミティブを使用することは、より優れた設計のようです。これは別の可能性です。

于 2012-09-05T17:11:36.370 に答える
1

生のポインターまたはスマートポインターを使用するかどうかに関係なく、Kerrekのソリューションは、コピーコンストラクター、デストラクタ、スワップを作成し、それらを使用して代入を実装する必要があるという意味で正しいです。

class Foo 
{
private:
    int* mInt_ptr;
    // many other member variables
    // of different types
public:
    Foo()
        : mInt_ptr(NULL)
        // initialize all other members
    {}
    Foo(const Foo& that)
        : mInt_ptr(new int(*that.mInt_ptr) )
        // copy-construct all other members
    {}
    Foo& operator=(const Foo& that)
    {
        // you may check if(this == &that) here
        Foo(that).swap(*this);
        return *this;
    }
    ~Foo()
    {
        delete mInt_ptr;
        // and release other resources
    }
    void swap(Foo& that)
    {
        std::swap(mInt_ptr, that.mInt_ptr);
        // swap all members
    }
};

メンバーは、コンパクトに保つ​​ためにここではインラインになっています。通常、インラインメンバー定義でクラス定義に負担をかけることはお勧めできません。

于 2012-09-05T17:23:55.883 に答える