【问题标题】:How to determine whether a c++ class is copyable如何判断一个c++类是否可复制
【发布时间】:2013-06-04 08:50:22
【问题描述】:

我有兴趣提高我对如何避免编写复制时导致问题的 C++ 类的理解。

特别是,我编写了一个名为Policy 的类,我打算复制它。我有 not 定义了非默认析构函数、复制构造函数或复制赋值运算符。我重载的唯一运算符如下:

friend bool operator== (const Policy& p1, const Policy& p2) {
    for(int i=0; i<p1.x.size(); i++) {
        if(p1.x[i] != p2.x[i])
            return false;
    }
    return true;
}

该类的成员要么是标准数据类型,例如 intdoubleboolstd::stringstd::vector&lt;double&gt;std::vector&lt;int&gt;std::vector&lt;string&gt;,要么是一些小的数据类型之一(因此不太复杂)我定义的类绝对是可复制的,没有任何问题。现在,Policy 的成员是 NRRan 类的一个实例,这是我构建的一个类,作为不可复制的第三方数据类型的包装器; NRRan如下:

class NRRan {
public:
    double doub() { return stream->doub(); }

    int intInterval(const int& LB, const int& UB) { return LB+int64()%(UB-LB+1); }

    void setNewSeed(const long& seed) {
        delete stream;
        stream = new Ranq1(seed);
    }    

    NRRan() { stream = new Ranq1(12345); }    

    ~NRRan() { delete stream; }

    NRRan(const NRRan& nrran) {
        stream = new Ranq1(12345);
        *stream = *(nrran.stream);
    }    

    NRRan& operator= (const NRRan& nrran) { 
        if(this == &nrran)
            return *this;    
        delete stream;
        stream = new Ranq1(12345);
        *stream = *(nrran.stream);    
        return *this;
    }

private:
    Ranq1* stream;  // underlying C-struct 
    Ullong int64() { return stream->int64(); }    
};

NRRan 类的全部意义在于使Ranq1 可复制。那么,鉴于我所描述的Policy 类(抱歉,我无法发布大部分代码),当我复制Policy 时是否有任何可能导致问题的事情?我的期望是复制将创造出完美的价值复制。

问我问题的更一般的方式如下:一般来说,在复制课程时,哪些类型的事情可能会导致问题?除了“三法则”之外还有什么(或“五法则”)在使类可复制时需要关注?

【问题讨论】:

  • 我认为在这种情况下你应该没问题。所有 Policy 类成员都可以通过浅拷贝(例如赋值运算符)进行复制,包括您的 NRRan 类,该类重载该运算符以正确复制 *stream 指针。您唯一需要担心的是复制指针。如果您的类处理诸如删除/生成该指针之类的事情,则弄乱一个类可能会弄乱副本,因此您将不得不在副本上复制指针。在其他情况下,只要不删除它们,让两个类引用相同的指针就可以了。
  • 谢谢。这就是我的想法(希望)。

标签: c++ class noncopyable


【解决方案1】:

嗯,这个问题有误导性..

一个线性答案可以是——使用std::is_copy_constructible 来确定一个类是否可以被复制。

【讨论】:

  • 这不起作用,std::is_copy_constructible 只检查类型是否不删除复制构造函数。例如,is_copy_constructible&lt;vector&lt;unique_ptr&lt;int&gt;&gt;&gt; 的计算结果为 true,但它并不是真正可复制的。
  • 是的,对于容器,我们需要更强大的检查。我会更新我的答案。
  • @markand g++clang++ 现在都将is_copy_constructible&lt;vector&lt;unique_ptr&lt;int&gt;&gt;&gt; 报告为false,所以它最终确实有效,至少对于std::unique_ptr
【解决方案2】:

如果一个类具有已删除或私有复制构造函数/赋值运算符,或者至少有一个成员具有已删除或私有复制构造函数/赋值运算符(递归应用),则该类是不可复制的。

示例:

#include <iostream>
#include <type_traits>

class A{

};

class B {
private:
    A a;
    B(const B&) = default;
    B& operator=(const B&) = default;
public:
    B() = default;
};

class NonCopyable {
    int i_;
public:
    NonCopyable() : i_{0}
    {}
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable& operator=(const NonCopyable&) = delete;
};


struct Composable {
    NonCopyable nc;
};

struct C {
    A a;
    B b;
};


int main()
{
    A a;
    A aa{a};                // copy construct
    A aaa = a;              // copy assign
    B b;
    //B bb{b};              // can't
    //B bbb = b;                // can't 
    NonCopyable nc;
    //NonCopyable nc2 = nc; // cannot
    //NonCopyable nc3{nc};  // cannot
    Composable comp;
    //Composable comp2{comp};   // can't copy construct either
    //Composable comp3 = comp;// can't copy assign either

    std::cout << std::boolalpha;
    std::cout << std::is_copy_assignable_v<A> << '\n';
    std::cout << std::is_copy_assignable_v<NonCopyable> << '\n';
    std::cout << std::is_copy_constructible_v<Composable> << '\n';
    std::cout << std::is_copy_constructible<C>::value << '\n';
}

输出

true
false
false
false

同样适用于不可移动的..

【讨论】:

  • 把那些不可复制的东西放在一个向量中 并且特征说真而不是假...
  • @ManuEvans 什么?你甚至不能在容器onlinegdb.com/Hytxj2-UP 中插入不可复制的对象。
猜你喜欢
  • 1970-01-01
  • 2020-02-14
  • 1970-01-01
  • 2019-09-14
  • 2013-07-11
  • 1970-01-01
  • 1970-01-01
  • 2013-01-14
  • 1970-01-01
相关资源
最近更新 更多