Inside The C++ Object Model 学习笔记(I)

最近一直在看 Inside The C++ Object Model, 希望从这本书中了解一下底层对象模型的设计,也为以后研究JVM的对象模型做铺垫。

注:由于这本书比较老,最新也就是C++ 98标准。因此这些总结都是基于C++ 98标准的。如果有C++ 11中新增的特性或新的优化(貌似析构函数那一部分变了挺多),我会单独指出。

这篇将总结C++的构造函数语义学相关的内容( Inside The C++ Object Model, Chapter 2 )。第二章主要讲述了构造函数的相关模型及事项。

Implicit Default Constructor(C++ 98)

在我们没有声明默认构造函数的时候,编译器有可能会为我们自动生成默认构造函数。不过,并非在所有情况下,编译器都自动生成default constructor。当且仅当以下四种情况下,编译器会自动为一个类生成default constructor:

  1. 此类有一个显式地实现了默认构造函数(explicit default constructor)的对象成员变量
  2. 此类的父类显式地实现了默认构造函数
  3. 此类中存在虚函数
  4. 此类间接继承了虚基类

注: C++ 11标准增加了移动构造函数(move constructor),有关移动构造函数相关的东西可以看C++ 11标准。

Copy Constructor(C++ 98)

No Bitwise copy

编译器不能简单地拷贝对象,因为编译器需要保证vptrvtbl的正确性。复制的时候要注意正确赋值。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A { // virtual base class
public:
explicit A() {}
explicit A(int i):i(i) {}
virtual ~A() {} // virtual deconstructor
virtual int test() {
return this->i;
}
protected:
int i;
};
class B : public virtual A {
};
class C : public virtual A {
};
class D : public b, public C {
};

如果在赋值的时候将sub object赋值给base object,编译器为了确保vptrvtbl的一致性,会对其截断:

1
A a = D{};

Return Value Initialization (Traditional C++)

注:C++ 11以后引入了Copy Elision可以省掉copy的过程。

1
2
3
4
5
6
7
Test genTest() {
Test test;
// do something to wrap the object ...
return test;
}

经过编译器解析后被转化为:

1
2
3
4
5
6
7
8
9
10
11
12
void genTest(Test& __temp) {
Test test;
// <init>
test.Test::Test();
// do something to wrap the object ...
// copy constructor invocation
__temp.Test::Test(test);
return;
}

现在如果执行Test t = genTest()这条语句的话,它会被编译器转化为:

1
2
Test t;
genTest(t);

RVO (Copy Elision)

C++ 11将Copy Elision优化加入C++标准中:

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

调用消耗:copy > move > RVO

浅拷贝和深拷贝

老生常谈的东西了,对于指针变量(或数组),必须执行按地址拷贝,这是默认生成的拷贝构造函数不能提供的。因此如果成员变量里有指针型或数组型变量,那么必须自己实现拷贝构造函数,用 memcpymemcopy 进行按地址拷贝。

Move Constructor(C++ 11)

待总结…


参考资料

文章目录
  1. 1. Implicit Default Constructor(C++ 98)
  2. 2. Copy Constructor(C++ 98)
    1. 2.1. No Bitwise copy
    2. 2.2. Return Value Initialization (Traditional C++)
    3. 2.3. RVO (Copy Elision)
    4. 2.4. 浅拷贝和深拷贝
  3. 3. Move Constructor(C++ 11)
  4. 4. 参考资料