显式禁止编译器生成的函数
Explicitly Disallowing Compiler Generated Functions
最近我一直在研究迈耶斯的有效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
对象本身。
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++作为特殊函数
调用乳清之所以如此称呼,特别是由于两个因素:
1.它们由编译器生成(如果不是由用户生成);
2. 它们将同一类的参数对象作为参数对象(~析构函数除外)。
因此,对于对象上的指针,不会生成此类函数。
同样在 C++ 11 标准中,您可以使用delete
语句,而不是声明要隐藏private
区域中的函数。
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 我需要知道编译器如何在cpp中使用析构函数
- 编译器如何区分std::vector的构造函数
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 填充上编译器生成的复制构造函数之间的不一致
- 编译器找不到'aligned_alloc'函数
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- 为什么编译器将其解析为函数指针而不是递归调用?
- 表达式未评估为常数两个级别的constexpr函数(编译器错误?)
- 从 std::streambif 继承时不兼容析构函数编译器警告
- 在构造函数 - 编译器错误中调用的成员变量的驱动器
- 复制初始化和显式构造函数-编译器的差异
- 静态函数编译器优化C++
- 为什么派生类虚函数可以调用基类虚函数?编译器如何实现
- 复制构造函数 - 编译器错误 C2040 和 C2440
- 带有模板返回类型的虚基函数:编译器在使用pointtype作为模板参数的派生类时失败(MSVC 2013)
- C++中虚拟函数编译器的作用