显式禁止编译器生成的函数 最近我一直在通过迈尔斯的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>&); };

显式禁止编译器生成的函数 最近我一直在通过迈尔斯的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>&); };,c++,C++,但是,当像这样使用时,代码可以很好地编译,并且可以在不应该能够进行复制的情况下进行复制 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->

但是,当像这样使用时,代码可以很好地编译,并且可以在不应该能够进行复制的情况下进行复制

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
对象本身


t1
t2
t3
t4
都指向同一个对象,并且这个对象永远不会被复制。

这里有两件重要的事情:

  • 类型和指向该类型的指针是两件截然不同的事情
  • 复制指针不会复制它指向的内容
  • 以这个区块为例:

    Test* t1 = new Test(), *t2;
    t1->test();
    // Works when it shouldnt work?
    t2 = t1;
    
    您的
    t1
    对象未复制到此处。内存中只有一个类实例,但现在有两个对它的引用。如果您在
    t2
    上调用
    delete
    ,它将销毁该单个副本,而您的另一个引用
    t1
    现在将指向无效的内存位置


    我不确定您是否可以阻止原始指针的复制,但即使可以,程序员也可以简单地将
    Test*
    强制转换为
    void*
    ,复制指针,然后将其强制转换回
    Test*
    。如果您想防止复制任何类型的引用,您将需要使用智能指针和私有构造函数,这是一个全新的问题生成函数>在C++标准中被称为<强>特殊函数>BR> 乳清被称为,特别是由于两个因素:
    1.由编译器生成(如果不是由用户生成)
    2。它们作为同一类的参数对象(除了~destructor)

    因此对于对象上的指针这样的函数不会生成

    同样在C++11标准中也可以使用
    delete
    语句,而不是在
    private
    区域中声明要隐藏的函数

    别那么做<代码>t2未初始化。。。这并不重要,它不应该像预期的那样坎皮尔。@Mankarse,它很好;不会调用赋值运算符,因此没有UB。对。。。对它不会编译。。。脸掌。
    *t2 = *t1;
    
    Test* t1 = new Test(), *t2;
    t1->test();
    // Works when it shouldnt work?
    t2 = t1;