关于 allocator, 即拆分 new 的行为(只调用 ::operator new(size_t) 而不调用相应类的构造函数,相当于 malloc),实现性能的提升。
#include <iostream>
#include <exception>
#include <vector>
//using namespace std;
// see links:
// http://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c4079/Allocators-STL.htm
// http://www.codeproject.com/Articles/4795/C-Standard-Allocator-An-Introduction-and-Implement
class Test
{
public:
Test()
{
std::cout << "Constructor" << std::endl;
}
~Test()
{
std::cout << "Destructor" << std::endl;
}
};
int main()
{
void * a = ::operator new(sizeof(Test)); // 分配内存
new (a) Test(); // 调用构造函数初始化
Test* b = static_cast<Test *>(a);
std::cout << "address: " << a << std::endl;
b->~Test(); // 调用析构函数
::operator delete(a); // 释放内存
std::cout << "address: " << a << std::endl;
return 0;
}
一般来说 new Test
的再编译的行为可以用一下代码表示:
Class Test;
Test* p;
// don't catch exceptions thrown by the allocator itself
void* raw = operator new(sizeof(Test));
// catch any exceptions thrown by the ctor
try {
p = new(raw) Test(); // call the ctor with raw as this
}
catch (...) {
// oops, ctor threw an exception
operator delete(raw);
throw; // rethrow the ctor's exception
}
因此,在 Test
的构造函数中抛异常不会导致 Test* p
的内存泄露,但是 Test
的析构函数不会被调用,由此可能在 Test
内部导致内存泄漏。
如果看到一个 placement new 带了参数,那么他会将这些参数传递给 operator new,
For example:
MyPtr ptr;
new(ptr, len, cont, scope) MyClass(len, name); # placement new with parameter...
这个操作相当于:
1. calls operator new(sizeof(MyClass), ptr, len, cont, scope)
# 前提是必须定义了 operator new(const size_t size, ---> 初始化为 sizeof(MyClass)
MyPtr& ptr,
int len,
MyCont& cont,
MyScope& scope)
2. 在 operator new 返回的内存块上(指针上),调用 MyClass 构造函数,
其效果就是,自定义分配一块内存,并且在该内存上调用构造函数,并且同时将一些参数传递到了底层用于决定如何分配内存。
更多关于 ::operator new & placement new
见下面链接:
https://eli.thegreenplace.net/2011/02/17/the-many-faces-of-operator-new-in-c
在 Inside the C++ Object Model 一书中强调, Menber Initialization List 是根据成员 在类中被声明的顺序 初始化的,而不是按照在 初始化列表中的顺序 初始化的!
如下对象:
#include <iostream>
class X
{
public:
X(int val):j(val),i(j) // i 先被声明,先初始化 i
{}
public:
int i; // 先被声明
int j;
};
int main()
{
X a(6);
std::cerr << "a.i: " << a.i << std::endl;
std::cerr << "a.j: " << a.j << std::endl;
}
// 编译的时候会有warning: [-Wreorder]
可能的输出:
a.i: -1218531328
a.j: 6
关于 NRVO 和 RVO 返回值优化,有人解释的很好,see link:
- http://stackoverflow.com/questions/5918312/what-rules-to-follow-for-a-function-to-use-nrv-optimization
- 甚至 Pass By Vaue 的参数也可以被优化:https://web.archive.org/web/20140113221447/http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/