为什么C ++ operator new / delete / variants不应该在头文件中?

时间:2016-09-05 05:13:03

标签: c++ gcc delete-operator translation-unit

有人可以解释这个C ++编译错误的本质吗?我正在涉及/学习重载全局运算符new,delete及其变体。我读了一个couple of articles on the subject,但我找不到一个似乎特别针对此问题的人。

守则

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之外阅读了一篇文章,提到这些运算符只能包含在一个&#34;翻译单元&#34;因此不应该在头文件中。我不明白翻译单元是什么,那篇文章没有解释它是什么。如果这与此问题有关,请解释一下&#34;翻译单元&#34;是为什么需要从头文件中排除函数声明 - 这似乎与我之前的所有C ++编码经验相悖。

感谢您的任何见解。

1 个答案:

答案 0 :(得分: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动态内存管理如果您有权访问它,可以获得有关该主题的更多信息。

翻译单元通常是.cpp文件。进一步阅读:What is a "translation unit" in C++