为什么 C++ 运算符 new/delete/variants 不应该在头文件中?
Why shouldn't C++ operator new/delete/variants be in header files?
谁能解释一下这个 C++ 编译错误的性质?我正在研究 in/learning 重载全局运算符 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);
^
我认为有关此问题的一些奇怪之处:
- 如果我在
foo.cpp
中注释掉#include <iostream>
,编译成功
- 如果我注释掉
foo.h
中的函数声明,只保留它们在foo.cpp
中的定义(同时保留#include <iostream>
),编译成功。
我有一些模糊的怀疑;也许回答者会通过他们的回答来确认:
- 错误提到了
exception specifier
所以我想也许通过覆盖这些运算符中的任何一个,我有义务覆盖他们兄弟姐妹的整个套件。但是,添加operator delete(void*, const std::nothrow_t&)
声明和定义并没有改变编译错误。我也不认为重写这些运算符中的任何一个都会迫使编码器实现所有这些运算符,但我是不是弄错了?
- 我在 Whosebug 之外阅读了一篇文章,提到这些运算符只能包含在一个 "translation unit" 中,因此不应包含在头文件中。我不明白什么是翻译单位,那篇文章也没有解释它是什么。如果这与此问题有关,请解释什么是 "translation unit" 以及为什么需要从头文件中排除函数声明 - 这似乎与我之前的所有 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 文件。延伸阅读:What is a "translation unit" in C++.
谁能解释一下这个 C++ 编译错误的性质?我正在研究 in/learning 重载全局运算符 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);
^
我认为有关此问题的一些奇怪之处:
- 如果我在
foo.cpp
中注释掉#include <iostream>
,编译成功 - 如果我注释掉
foo.h
中的函数声明,只保留它们在foo.cpp
中的定义(同时保留#include <iostream>
),编译成功。
我有一些模糊的怀疑;也许回答者会通过他们的回答来确认:
- 错误提到了
exception specifier
所以我想也许通过覆盖这些运算符中的任何一个,我有义务覆盖他们兄弟姐妹的整个套件。但是,添加operator delete(void*, const std::nothrow_t&)
声明和定义并没有改变编译错误。我也不认为重写这些运算符中的任何一个都会迫使编码器实现所有这些运算符,但我是不是弄错了? - 我在 Whosebug 之外阅读了一篇文章,提到这些运算符只能包含在一个 "translation unit" 中,因此不应包含在头文件中。我不明白什么是翻译单位,那篇文章也没有解释它是什么。如果这与此问题有关,请解释什么是 "translation unit" 以及为什么需要从头文件中排除函数声明 - 这似乎与我之前的所有 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 文件。延伸阅读:What is a "translation unit" in C++.