简体   繁体   English

手动仅定义复制构造函数和赋值运算符的一部分

[英]Manually define only part of copy constructor and assignment operator

I'm wondering if there is a way to implement copy constructors and assignment operators such that only a small modification is needed when these are redefined for a class. 我想知道是否有一种方法可以实现复制构造函数和赋值运算符,以便在为类重新定义它们时只需要进行少量修改即可。

For example, consider a class as such: 例如,考虑一个这样的类:

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();
};

Now, in order to deal with the pointer mInt_ptr I would need to handle it appropriately in the copy constructor and assignment operator. 现在,为了处理指针mInt_ptr我需要在复制构造函数和赋值运算符中对其进行适当处理。 However, the rest of the member variables are safe to do a shallow copy of. 但是,其余成员变量可以安全地进行浅表复制。 Is there a way to do this automatically? 有没有一种方法可以自动执行此操作?

Once a class becomes large it may become tedious and unwieldy to explicitly write out the operations to copy the non-pointer member variables, so I'm wondering if there is a way to write, say, a copy constructor such as: 一旦类变大,显式地写出用于复制非指针成员变量的操作可能会变得乏味且笨拙,因此我想知道是否存在一种方法来编写复制构造函数,例如:

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

rather than the explicit form of: 而不是以下形式的显式形式:

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

Generally, don't use raw pointers, for exactly the reason that you're now fighting with. 通常,不要使用原始指针,这正是您现在正在使用的原因。 Instead, use a suitable smart pointer, and use copy-swap assignment: 而是使用合适的智能指针,并使用复制交换分配:

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); } }

The value_ptr could be a full-blown implementation , or something simple such as this: 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; }
};

How about you wrap all the shallow-copy bits in a small helper struct and use the default copy behaviour there. 您如何将所有浅拷贝位包装在一个小的辅助结构中,并在那里使用默认的拷贝行为。

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;
}

Using better primitives, as Kerrek suggested, seems like better design though. 正如Kerrek建议的那样,使用更好的原语似乎是更好的设计。 This is just another possibility. 这只是另一种可能性。

Regardless if you use raw pointers or smart pointers the Kerrek's solution is right in the sense that you should make a copy constructor, destructor and swap and implement assignment using those: 不管您使用原始指针还是智能指针,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
    }
};

The members are inline here just to keep it compact, usually it is not advisable to burden class definition with inline member definitions. 成员在这里是内联的,只是为了保持紧凑性,通常不建议在类定义中加入内联成员定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM