【发布时间】:2013-07-23 12:34:07
【问题描述】:
当我发现一些奇怪的东西时,我正在使用重载的 new 和 delete 运算符。
-
我有:
void* operator new(size_t size) { std::cout << "Allocating memory..." << std::endl; void* p = malloc(size); if (NULL == p) { throw std::bad_alloc(); } return p; } -
当我这样做时:
int main() { int* x = new int(1); std::cout << *x << std::endl; delete x; return EXIT_SUCCESS; }一切都按预期进行,我得到:
Allocating memory... 1 -
但是当我这样做时:
int main() { std::string* s = new std::string("Hello world"); std::cout << *s << std::endl; delete s; return EXIT_SUCCESS; }我明白了:
Allocating memory... Allocating memory... Hello world -
事实上,当我这样做时:
int main() { std::string s = "Hello world"; return EXIT_SUCCESS; }我仍然得到
Allocating memory...! -
最后,我做到了:
int main() { std::string s = "Hello world"; std::cout << &s << std::endl; while (true); }得到类似的东西:
$ ./test & [1] 8979 Allocating memory... 0xbfc39a68 $ cat /proc/8979/maps | grep stack bfc27000-bfc3c000 ... [stack]所以现在我确定
s变量是在堆栈上分配的......但是,什么叫new运算符?我最好的猜测是它与实际文字的内存分配有关,"Hello world"... 但它应该是静态内存,new是关于动态内存的。
发生了什么事?
更新
在阅读了 cmets 并亲自调试了示例之后,我想得出结论,确实,一旦调用了字符串构造函数,它就会在堆上为其内部实现分配内存。这可以通过跟踪new 调用来查看:
(gdb) b 13 // that's the std::cout << "Allocating memory..." << std::endl; line
(gdb) r
... Breakpoing 1, operator new (size=16) at test.cpp:13 ...
(gdb) backtrace
#0 operator new (size=16) at main.cpp:13
#1 std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) () from /usr/lib/libstdc++.so.6
...
并阅读 std::string(好吧,basic_string.tcc)源代码:
template<typename _CharT, typename _Traits, typename _Alloc>
typename basic_string<_CharT, _Traits, _Alloc>::_Rep*
basic_string<_CharT, _Traits, _Alloc>::_Rep::
_S_create(size_type __capacity, size_type __old_capacity,
const _Alloc& __alloc)
{
...
void* __place = _Raw_bytes_alloc(__alloc).allocate(__size);
_Rep *__p = new (__place) _Rep; // Bingo!
__p->_M_capacity = __capacity;
...
}
是的。编程很酷。
【问题讨论】:
-
注意:
malloc/free和new/delete- 是一对 -
你为什么不使用调试器并打破你的
operator new看看是谁在调用它?流也会分配内存。 -
std::string的全部意义在于它封装了一个char*并为您拥有/管理它。因此,当您创建std::string时,它会分配一些内存来存储实际字符。构造函数甚至可以采用自定义分配器。 -
@GrijeshChauhan:我还通过
free实现了delete,如果这就是你的意思,但它与问题无关,所以我省略了。 -
不会是代码 3 中的
std::string *s吗?