如果操作符delete没有实现,为什么不编译它
why does this not compile if operator delete has no implementation
如果操作符delete没有实现,为什么不编译?
class A
{
public:
virtual ~A(){ }
private:
void operator delete(void *p);
};
int main()
{
A a;
}
使用g++编译,得到以下错误:
对"A::operator delete(void*)"的未定义引用
如果给它一个空的操作员删除的实现
class A
{
public:
virtual ~A(){ }
private:
void operator delete(void *p) {}
};
int main()
{
A a;
}
或删除"虚拟"
class A
{
public:
~A(){ }
private:
void operator delete(void *p);
};
int main()
{
A a;
}
两者都编译成功。
如何解释?
好吧,之间有很大的区别
void operator delete(void *p);
和
void operator delete(void *p) {}
前者只是声明函数;后者定义了它。当你声明一个函数时,你基本上只是说"有一个函数,这里是它的参数类型和返回值",但当你定义一个函数的时候,你写下了实际包含该函数的代码。用一对空大括号定义的函数什么也不做;一个已声明但未定义的函数可能会做任何事情(只有看到定义后才能知道)。显然,除非已经定义了函数,否则不能调用它。不太明显的是,除非已经定义了函数,否则函数的地址不能被占用。显然,这两种语句都意味着,如果您调用一个函数或获取函数的地址,而您未能定义它,那么您的程序就是格式错误的。
通常,未能定义需要定义的内容的结果是链接器错误。这是因为当你以需要定义的方式使用某个东西时,编译器会创建一个符号,告诉链接器在找到定义后将地址插入所需的位置。如果链接器找不到定义(因此也找不到地址),那么它就无法完成它的工作。
C++标准有一组神秘的规则,基本上告诉你在什么条件下需要定义函数。有时是,有时不是。一个微不足道的例子:
int f();
int main() {}
这很好;函数f
从不被隐式或显式地调用;其地址从未被占用;它甚至没有被调用的机会。因此,即使未定义f
,该程序也将进行编译。
根据标准,如果函数odr使用,则必须定义该函数。关于operator delete
([basic.def.odr]/3),该标准有以下内容:
的非放置分配或解除放置函数一个类是odr,用于定义该类的构造函数。的非放置解除分配函数类的析构函数的定义使用odr,或者通过在虚拟析构函数的定义要点(12.4)。(脚注26)。。。
因此:如果您的类定义了构造函数或析构函数,它将使用您的operator delete
。因此,你的析构函数是否是虚拟的并不重要;由于您定义了析构函数,因此如果没有operator delete
的定义,您的程序将是格式错误的。[1]
现在,您可能会问,当析构函数是非虚拟的时,为什么编译器和链接器不抱怨。好吧,工具链有时会接受代码,即使它们应该拒绝它。在这种特殊的情况下,如果析构函数不是虚拟的,那么你的程序实际上不需要operator delete
的地址,所以如果你从不定义它,链接器不会抱怨。但当你使析构函数成为虚拟的时,由于解除分配函数的查找基于要解除分配的对象的动态类型,因此需要为解除分配函数提供vtable条目,这意味着必须知道其地址。因此出现了链接错误。(我想再次重申,即使当析构函数是非虚拟的时,编译器和链接器接受代码,但根据我对标准的阅读,它仍然是格式错误的代码。)
[1] 请注意,只要您实际创建了A
类型的对象,就不可能没有构造函数和析构函数的定义,即使您自己没有定义它们;也就是说,编译器将隐式生成定义。)
- 为什么 emscripten 不编译我的函数?
- 我不明白为什么会编译
- 为什么不编译 OpenGL 着色器?
- 为什么 std::atom::is_lock_free 不编译?
- 为什么Visual Studio 2019不编译我的代码?
- 为什么这种转换方法不编译?
- 为什么对数组的常量左值引用不编译在下面?
- 为什么"cout << Color::green"不编译?
- 为什么"0xe+1"不编译?
- 为什么不编译?特里波那契函数
- 为什么不编译以下 CRTP 层次结构?
- 为什么不编译?与"运算符&="不匹配
- 如果(a)b=c,d=e,return;,为什么不编译
- 如果操作符delete没有实现,为什么不编译它
- 为什么不编译此代码
- 为什么不编译?(VC++ 2015,#pragma omp flush)
- 为什么不编译带有函数指针的代码?
- Boost日志-为什么不编译
- C++:为什么不编译?
- 使用非多态类向下转换dynamic_cast,为什么不编译?