隐藏复制构造函数C ++

时间:2012-01-30 17:26:53

标签: c++ copy-constructor

我想创建无法复制的类,所以我将复制构造函数放入私有部分:

class NotCopyable
{
public:
    NotCopyable(const double& attr1, const double& attr2) : _attr1(attr1), _attr2(attr2) {}
    ~NotCopyable(void) {}

private:
    NotCopyable& operator=(const NotCopyable&);
    NotCopyable(const NotCopyable&);
    double _attr1;
    double _attr2;
};

除非我想分配数组,否则一切正常:

NotCopyable arr[] =
{
    NotCopyable(1, 0),
    NotCopyable(2, 3)
};

编译器说她无法访问复制构造函数,因为它在私有部分中。 当我把它放在公共区域时:

class NotCopyable
{
public:
    NotCopyable(const double& attr1, const double& attr2) : _attr1(attr1), _attr2(attr2) {}
    ~NotCopyable(void) {}
    NotCopyable(const NotCopyable&)
    {
        std::cout << "COPYING" << std:: endl;
    }
private:
    NotCopyable& operator=(const NotCopyable&);

    double _attr1;
    double _attr2;
};

程序编译没有错误,但不调用复制构造函数。所以问题是:我如何禁止复制但仍有可能分配数组?

3 个答案:

答案 0 :(得分:7)

您的代码arr [] = { NotCopyable(1,2) };确实请求复制构造函数,至少是正式的。实际上,副本通常被省略,但这属于“as-if”规则,并且复制构造函数仍然必须是可访问的,即使最终它没有被使用。 (在GCC中,您可以说-fno-elide-constructors实际调用复制构造函数。)

你无法在C ++ 03中解决这个问题,其中大括号初始化总是需要正式的副本。在C ++ 11中,您可以使用大括号初始化来直接初始化数组成员,但是:

NotCopyable arr[] { {1, 0}, {2, 3} };

即使没有可访问的复制构造函数,也可以使用。

答案 1 :(得分:1)

这是不正确的,因为您使用必须通过复制创建的对象数组:

#include <vector>
using namespace std;

class NotCopyable
{
public:
    NotCopyable(const double& attr1, const double& attr2) : _attr1(attr1), _attr2(attr2) {}
    ~NotCopyable(void) {}

private:
    NotCopyable& operator=(const NotCopyable&);
    NotCopyable(const NotCopyable&);
    double _attr1;
    double _attr2;
};

int main()
{
    vector<NotCopyable> v;
    NotCopyable a(1, 2);
    v.push_back(a); // THIS IS COPYING
    return 0;
}

由于您已禁用复制,因此您只能存储参考。你应该把它作为指针

的数组
NotCopyable a(1, 2);

// incorrect:
vector<NotCopyable> v;
v.push_back(a);

// correct:
vector<NotCopyable*> v2;
v2.push_back(&a);

希望这会有所帮助;)

答案 2 :(得分:0)

NotCopyable arr[] =
{
    NotCopyable(1, 0),
    NotCopyable(2, 3)
};

编写时,编译器需要copy-constructor,因为它是 copy-initialization 。这就是为什么你得到编译错误,因为复制构造函数被声明为private,因此它无法从外部访问。但是,如果在public部分中定义它,那么它可以工作,但是不会调用copy-constructor,这是因为编译器完成了优化。规范允许编译器在这种情况下忽略复制构造函数的调用,但是它仍然需要 accessible 复制构造函数,仅用于代码的语义检查。一旦完成语义检查,它就不会被调用!