为什么C++运算符 new/delete/variant 不应该出现在头文件中?



谁能解释一下这个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);
      ^

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

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

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

  • 这个错误提到了一个exception specifier,所以我想也许通过重写这些操作符中的任何一个,我有义务重写它们的兄弟姐妹的整个套件。然而,添加operator delete(void*, const std::nothrow_t&)声明和定义并没有改变编译错误。我也不认为它应该是真的,重写任何这些操作符强制编码实现所有这些,但我错了吗?
  • 我在StackOverflow之外读到一篇文章,提到这些操作符必须只包含在一个"翻译单元"中,因此不应该在头文件中。我不明白什么是翻译单位,那篇文章也没有解释什么是翻译单位。如果这与这个问题有关,请解释一下什么是"翻译单元",以及为什么需要从头文件中排除函数声明——这似乎与我以前所有的c++编码经验相反。

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

库将operator delete函数声明为:

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

而你声明它们为:

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

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

#include <new>

查找部分18.6动态内存管理的c++ 11标准,如果你有更多的信息可以访问它。

翻译单元通常是一个.cpp文件。读后感:什么是"翻译单元";在c++中,

相关内容

  • 没有找到相关文章

最新更新