显式禁止编译器生成的函数

Explicitly Disallowing Compiler Generated Functions

本文关键字:函数 编译器 禁止      更新时间:2023-10-16

最近我一直在研究迈耶斯的有效C++第三版。对于我目前正在处理的一个项目,我必须创建一个我明确希望禁止使用编译器生成的函数的类。我使用上述书中的第 6 项作为参考实现了代码,唯一的主要区别是我的类是模板化的。它的代码如下

template <class T>
class Uncopyable
{
protected:
    Uncopyable<T>(){}
    virtual ~Uncopyable<T>(){}
private:
    Uncopyable<T>(const Uncopyable<T>&);
    Uncopyable<T>& operator=(const Uncopyable<T>&);
};

我的测试功能。

class Test : private Uncopyable<Test>
{
public:
    Test(){}
    ~Test(){}
    inline void test()
    {
        std::cout << "blah" << std::endl;
    }
private:
protected:
};

当像这样使用时,代码完全按预期工作

int main(int argc, char* argv[])
{
    Test t1, t2;
    // Works as expected, doesnt allow copying of object
    t2 = t1;
    // and this works fine, no copying
    Test t3 = t2;
    // finally, works correctly no copying is allowed
    Test t4(t1);
    return 0;
}

但是,当这样使用时,代码编译良好,并且可以进行复制,而何时应该不能?

int main(int argc, char* argv[])
{
    Test* t1 = new Test(), *t2;
    t1->test();
    // Works when it shouldnt work?
    t2 = t1;
    t2->test();
    // same with this
    Test* t3 = t2;
    t3->test();
    // and this
    Test* t4(t1);
    t4->test();
    delete t1;
    return 0;
}

我已经在没有模板类的情况下尝试过,结果是一样的,所以我认为这不是问题所在。

那么,为什么允许这种情况发生呢?我的代码中是否有错误,或者我只是理解错误的概念?谢谢。

您复制的是指针,而不是对象。 试试这个:

*t2 = *t1;

更改的代码是复制指针,而不是Test对象本身。

t1t2t3t4最终都指向同一个对象,并且该对象永远不会被复制。

这里有

两件重要的事情:

  1. 类型和指向该类型的指针是两个非常不同的东西。
  2. 复制
  3. 指针不会复制它指向的内容。

以这个块为例:

Test* t1 = new Test(), *t2;
t1->test();
// Works when it shouldnt work?
t2 = t1;

您的t1对象不会复制到此处。内存中只有一个类实例,但现在有两个对它的引用。如果您在 t2 上调用 delete,它将销毁该单个副本,并且您的另一个引用 t1 现在将指向无效的内存位置。

我不确定您是否可以阻止原始指针的复制,但即使可以,程序员也可以简单地将您的Test*转换为void*,复制指针,然后将其转换回Test*。如果你想防止复制任何类型的引用,你将需要使用智能指针和私有构造函数,这是一个全新的问题!

编译器

生成的函数标准C++作为特殊函数
调用乳清之所以如此称呼,特别是由于两个因素:
1.它们由编译器生成(如果不是由用户生成);
2. 它们将同一类的参数对象作为参数对象(~析构函数除外)。

因此,对于对象上的指针,不会生成此类函数。
同样在 C++ 11 标准中,您可以使用delete语句,而不是声明要隐藏private区域中的函数。