12

有人可以解释这个 C++ 编译错误的性质吗?我正在涉足/学习重载全局运算符 new、delete 及其变体。我阅读了几篇 关于这个主题 文章 ,但我找不到一篇似乎专门解决这个问题的文章。

编码

foo.h

#ifndef foo_h
#define foo_h

void* operator new(size_t);
void* operator new[](size_t);

void operator delete(void*);
void operator delete[](void*);

#endif // foo_h

foo.cpp

#include <foo.h>
#include <iostream>

void* operator new(size_t size) { return NULL; }
void* operator new[](size_t size) { return NULL; }

void operator delete(void* p) { }
void operator delete[](void* p) { }

编译错误

>g++ -g -std=c++14 -I./ -c foo.cpp -o foo.o
In file included from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/ext/new_allocator.h:33:0,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/x86_64-pc-cygwin/bits/c++allocator.h:33,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/allocator.h:46,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/string:41,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/locale_classes.h:40,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/ios_base.h:41,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/ios:42,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/ostream:38,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/iostream:39,
                 from foo.cpp:2:
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/new:116:41: error: declaration of ‘void operator delete(void*) noexcept’ has a different exception specifier
   __attribute__((__externally_visible__));
                                         ^
In file included from foo.cpp:1:0:
./foo.h:8:6: error: from previous declaration ‘void operator delete(void*)’
 void operator delete(void* p);
      ^
In file included from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/ext/new_allocator.h:33:0,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/x86_64-pc-cygwin/bits/c++allocator.h:33,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/allocator.h:46,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/string:41,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/locale_classes.h:40,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/ios_base.h:41,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/ios:42,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/ostream:38,
                 from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/iostream:39,
                 from foo.cpp:2:
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/new:118:41: error: declaration of ‘void operator delete [](void*) noexcept’ has a different exception specifier
   __attribute__((__externally_visible__));
                                         ^
In file included from foo.cpp:1:0:
./foo.h:9:6: error: from previous declaration ‘void operator delete [](void*)’
 void operator delete[](void* p);
      ^

关于这个问题的一些奇怪之处我认为是相关的:

  • 如果我注释掉#include <iostream>foo.cpp编译成功
  • 如果我注释掉 中的函数声明,并且foo.h只保留它们的定义,则编译成功。foo.cpp#include <iostream>

我有一些模糊的怀疑;也许回答者会通过他们的回答来确认:

  • 该错误提到了一个,exception specifier所以我想也许通过覆盖这些运算符中的任何一个,我有义务覆盖他们的兄弟姐妹的整个套件。但是,添加operator delete(void*, const std::nothrow_t&)声明和定义并没有改变编译错误。我也不认为重写这些运算符中的任何一个会迫使编码器实现所有这些运算符是正确的,但我错了吗?
  • 我在 StackOverflow 之外阅读了一篇文章,提到这些运算符只能包含在一个“翻译单元”中,因此不应包含在头文件中。我不明白什么是翻译单元,那篇文章也没有解释它是什么。如果这与这个问题有关,请解释什么是“翻译单元”以及为什么需要从头文件中排除函数声明——这似乎与我之前的所有 C++ 编码经验背道而驰。

感谢您的任何见解。

4

1 回答 1

5

您看到的问题是由于以下声明中的差异造成的。

该库将operator delete函数声明为:

void operator delete(void*) noexcept;
void operator delete [](void*) noexcept;

当您将它们声明为:

void operator delete(void*);
void operator delete [](void*);

而不是在您的 .h 文件中声明它们,您应该使用

#include <new>

如果您有权访问 C++11 标准的第 18.6 节动态内存管理以获取有关该主题的更多信息,请查阅第18.6 节。

翻译单元通常是 .cpp 文件。进一步阅读:什么是 C++ 中的“翻译单元”

于 2016-09-05T05:42:31.640 回答