Mysterious c++  Traps, Pitfalls and Secrets                          Kent Wang                          Jun 1, 2012
Why this talk• 警惕靠巧合编程• 勿在浮沙筑高台• 了若指掌方可收放自如• 见山非山, 见水非水
C++很____
C++很____
简单C++很____
猜猜我是谁Foo<T> bar;
猜猜我是谁Foo<T> bar;template <typename T>class Foo {  ...};
猜猜我是谁Foo<T> bar;template <int T>class Foo {  ...};
猜猜我是谁Foo<T> bar;int Foo;int T;int bar;
仇者联盟大战超人Foo<T> bar;Superman Foo;Spiderman T;Ironman bar;
sizeofclass A {   class B {    class C {};             char c;      virtual void foo();            };              char c;...
sizeofclass A {       class B {    class C {};                 char c;      virtual void foo();                };         ...
sizeofclass A {       class B {        class C {};                 char c;          virtual void foo();                }; ...
sizeofclass A {       class B {        class C {};                 char c;          virtual void foo();                }; ...
Constructorclass Animal { public:   Animal() {     Animal("Lion", 21);     Run();   }     Animal(const string& name, int a...
Constructorclass Animal { public:   Animal() {     Animal("Lion", 21);     Run();   }     Animal(const string& name, int a...
颤抖吧! 地球人!
简单C++很____
C++很____
C++很____
恐怖C++很____
Function Object       Member Function pointer                      Temporal Object                       dynamic_cast Func...
知乎?•   构造和析构函数机制是如何实现的?•   函数调用是如何传递及返回对象的?•   函数重载是如何实现的?•   多态是如何实现的?•    常机制是如何实现的?为何我们不用?•   静态变量是如何初始化的?
Tips 1           Dont live with         unknown unknowns
What to talk• C++语言演化历史• Object Memory Layout• 函数调用语义及临时对象• 静态变量初始化
What NOT to talk• 语法细节• 二进制兼容性• Exception Handling• Template & Generic Programming• C++11 (C++0x)
Outline•   青梅煮酒论英雄•   天机亦可泄露    -   对象内存模型    -   函数转换    -   函数调用    -   临时对象
青梅煮酒论英雄
Timeline                                                            2011   1980                1989                       ...
C++看起来像是...
C++看起来像是...
缘起               值语义零负担        C兼容性                惯用法 编译器隐 藏操作
C兼容性• class Foo{};  - unnamed structure in C• Header File• Preprocessor / macros
C兼容性• class Foo{};  - unnamed structure in C   struct {                                int a;                             ...
零负担• 不对栈变量自动初始化• Object on Stack• 默认构造函数不对POD类型进行初始化• 成员函数默认为非虚函数
值语义Person kent("kent");                             kent   "kent"
值语义Person kent("kent");Person lazy = kent;      kent       "kent"                             lazy   "kent"
引用语义Person kent("kent");                          kent   "kent"
引用语义Person kent("kent");Person lazy = kent;       kent                                 "kent"                          lazy
Not very good at OO• No reflection and dynamic creation• Object lifetime management• Complex syntax stops refactoring tools
既然如此,为什么我们还要用C++
C++ is deterministic
C++ is deterministic• Destructing is determinate  - No GC• Performance is predictable  - C++ is fast only when coders are ...
Where the Focus Is           Efficiency    Flexibility   Abstraction   Productivity   C                                   n...
Conclusion• There are only two kinds of languages  - The ones people always complain about  - The ones nobody uses• C++ is...
天机亦可泄漏
对象内存模型
简单对象class Animal { public:   void Run();  private:   char* name;   int age;   char sex;};
简单对象class Animal {                name public:   void Run();  private:                    age   char* name;   int age;   c...
单一继承class Animal { public:   void Run();  private:   char* name;   int age;   char sex;};class Lion : public Animal {  pri...
单一继承class Animal {                       address public:   void Run();  private:                            name   char* n...
虚函数   class Animal {    public:      void Run();      virtual void Say();     private:      char* name;      int age;     ...
虚函数   class Animal {                       vptr    public:      void Run();      virtual void Say();               name   ...
vptr and vtbl      vptr      name      ageSex    Alignment
vptr and vtbl      vptr         0   type_info    type_info      name         1     Say       &Animal::Say      ageSex    A...
带虚函数的继承class Animal { public:   virtual void Run();   virtual void Say();  private:   char* name;   int age;   char sex;};...
带虚函数的继承class Animal { public:   virtual void Run();   virtual void Say();         vptr  private:                          ...
vptr and vtbl      vptr      name      ageSex    Alignment
vptr and vtbl      vptr         0    type_info    type_info      name         1      Run       &Animal::Run      age      ...
M o re• 多重继承• 带虚函数的多重继承• 虚继承• 带虚函数的虚继承• 多重虚继承
函数转换 class Animal {  public:    void Run();   private:    ... }; Animal a; a.Run();* 真实情况下编译器会对函数名称进行编码,即name mangling.
函数转换 class Animal {  public:    void Run();   private:    ... }; Animal a; a.Run();* 真实情况下编译器会对函数名称进行编码,即name mangling.
函数转换 class Animal {                    void Animal_Run(Animal* this)  public:                          {    void Run();   ...
函数转换 class Animal {                    void Animal_Run(Animal* this)  public:                          {    void Run();   ...
虚函数转换class Animal { public:   void Run();   virtual void Say();  private:   ...};Animal a;a.Say();Animal* p = &a;p->Say();
虚函数转换class Animal {              void Animal_ctor(Animal* this) public:                    {   void Run();                ...
虚函数转换class Animal {              void Animal_ctor(Animal* this) public:                    {   void Run();                ...
函数调用• 对象类型参数传递• 对象类型参数返回• 临时对象• Return Value Optimization
简单类型函数调用int sum(int a, int b) {   int result = a + b;   return result;}int main(int argc, char* argv[]){   sum(1, 4);   re...
简单类型函数调用                                   ...int sum(int a, int b) {   int result = a + b;              4   return result...
简单类型函数调用                                        ...int sum(int a, int b) {   int result = a + b;                   4   ret...
简单类型函数调用                                              ...int sum(int a, int b) {             5   int result = a + b;      ...
类类型参数传递class Money { public:   Money Add(Money money);  private:   uint64_t amount;};Money item(700);Money freight(10);Mon...
类类型参数传递                                         ...class Money { public:   Money Add(Money money);         temp - Money(10...
类类型参数传递                                         ...class Money { public:   Money Add(Money money);         temp - Money(10...
类类型参数传递                                               ...class Money { public:   Money Add(Money money);               tem...
类类型返回值class Money { public:   Money Add(Money money);  private:   uint64_t amount;};Money item(700);Money freight(10);Mone...
类类型返回值class Money {                      void Money_Add( public:                               Money* this,   Money Add(Mo...
类类型返回值class Money {                      void Money_Add( public:                               Money* this,   Money Add(Mo...
临时对象• 函数调用的参数传递与返回• 额外的对象构造与析构• 额外的对象拷贝• 可能戏剧性的影响程序效率
Tips 2   Prefer pass-by-reference      to pass-by-value
Return Value Optimizationvoid Money_Add(  Money* this,  Money* ret,  Money money){  Money result = ...;  *ret = result;}Mo...
Return Value Optimizationvoid Money_Add(                     void Money_Add(  Money* this,                        Money* t...
Return Value Optimizationvoid Money_Add(                     void Money_Add(  Money* this,                        Money* t...
std::string• Implementations  - Eager Copy  - CoW - Copy on Write  - SSO - Small String Optimization
Copy on Write         string   data : char*
Copy on Write    string            "hello"data : char*                     5 30 1 h e   l   l   o ...
Copy on Write    string              "hello"data : char*                        capacity                      5 30 1 h e  ...
SSO      stringdata : char*size : size_tcapacity : size_tbuffer : char[16]
Small String      string                "hello"data : char*                          0x12345678size : size_tcapacity : siz...
Big String"hell ..."        h e   l   l ...0x12345678   20   32
Tips 3  Critically Analyze What   You Read And Hear
静态变量初始化Animal animal("Lion");int Foo() {   ...}int num = Foo();
静态变量初始化Animal animal("Lion");   void __sti_ii() {                           animal.Animal::Animal();int Foo() {           ...
inline vs. iteratorvector<int>::iterator it = vec.begin();vector<int>::iterator end = vec.end();    for (vector<int>::iter...
inline vs. iteratorvector<int>::iterator it = vec.begin();vector<int>::iterator end = vec.end();    for (vector<int>::iter...
inline vs. iteratorvector<int>::iterator it = vec.begin();vector<int>::iterator end = vec.end();    for (vector<int>::iter...
Tips 4         Dont Assume It,            Prove It
Prove I t!• Only Code Never Lies• Assembly Language• g++  - -S• nm
References• Bjarne Stroustrup. 1994. The Design And  Evolution of C++• Stanley B. Lippman. 1996. Inside the C++  Object Mo...
Q&A
Thanks for your time
Mysterious c++
Mysterious c++
Mysterious c++
Mysterious c++
Upcoming SlideShare
Loading in …5
×

Mysterious c++

819 views

Published on

Published in: Technology, Sports
  • Be the first to comment

Mysterious c++

  1. 1. Mysterious c++ Traps, Pitfalls and Secrets Kent Wang Jun 1, 2012
  2. 2. Why this talk• 警惕靠巧合编程• 勿在浮沙筑高台• 了若指掌方可收放自如• 见山非山, 见水非水
  3. 3. C++很____
  4. 4. C++很____
  5. 5. 简单C++很____
  6. 6. 猜猜我是谁Foo<T> bar;
  7. 7. 猜猜我是谁Foo<T> bar;template <typename T>class Foo { ...};
  8. 8. 猜猜我是谁Foo<T> bar;template <int T>class Foo { ...};
  9. 9. 猜猜我是谁Foo<T> bar;int Foo;int T;int bar;
  10. 10. 仇者联盟大战超人Foo<T> bar;Superman Foo;Spiderman T;Ironman bar;
  11. 11. sizeofclass A { class B { class C {}; char c; virtual void foo(); }; char c; };
  12. 12. sizeofclass A { class B { class C {}; char c; virtual void foo(); }; char c; }; 1
  13. 13. sizeofclass A { class B { class C {}; char c; virtual void foo(); }; char c; }; 1 4
  14. 14. sizeofclass A { class B { class C {}; char c; virtual void foo(); }; char c; }; 1 4 8
  15. 15. Constructorclass Animal { public: Animal() { Animal("Lion", 21); Run(); } Animal(const string& name, int age); virtual void Run() = 0;};
  16. 16. Constructorclass Animal { public: Animal() { Animal("Lion", 21); Run(); } Animal(const string& name, int age); virtual void Run() = 0;};
  17. 17. 颤抖吧! 地球人!
  18. 18. 简单C++很____
  19. 19. C++很____
  20. 20. C++很____
  21. 21. 恐怖C++很____
  22. 22. Function Object Member Function pointer Temporal Object dynamic_cast Function pointer Pass By Reference Pure Virtual Class RTTI typeid Overloading Pass By Value Pure Virtual FunctionCopy Constructor Virtual Function Multiple Inheritance Constructor Dynamic Binding Inheritance Exception Destructor Class Virtual Inheritance Friend Template String AdaptorNamespace STL Operator New RAII Iterator Function Template Class Template Template Specialization Memory Management Partial Specialization Smart Pointer Reference Preprocessor Template Meta Programming
  23. 23. 知乎?• 构造和析构函数机制是如何实现的?• 函数调用是如何传递及返回对象的?• 函数重载是如何实现的?• 多态是如何实现的?• 常机制是如何实现的?为何我们不用?• 静态变量是如何初始化的?
  24. 24. Tips 1 Dont live with unknown unknowns
  25. 25. What to talk• C++语言演化历史• Object Memory Layout• 函数调用语义及临时对象• 静态变量初始化
  26. 26. What NOT to talk• 语法细节• 二进制兼容性• Exception Handling• Template & Generic Programming• C++11 (C++0x)
  27. 27. Outline• 青梅煮酒论英雄• 天机亦可泄露 - 对象内存模型 - 函数转换 - 函数调用 - 临时对象
  28. 28. 青梅煮酒论英雄
  29. 29. Timeline 2011 1980 1989 C++11C with class CFront 2.0 1992 HP C++ Lambda Expression Class Multiple Inheritance Automatic TypeInheritance Abstract Class Exception Threading 1983 - 1986 1991 1996 C++ - CFront 1.1 CFront 3.0 C++ 98/03 Virtual Function Template STL Overloading Namespace Reference
  30. 30. C++看起来像是...
  31. 31. C++看起来像是...
  32. 32. 缘起 值语义零负担 C兼容性 惯用法 编译器隐 藏操作
  33. 33. C兼容性• class Foo{}; - unnamed structure in C• Header File• Preprocessor / macros
  34. 34. C兼容性• class Foo{}; - unnamed structure in C struct { int a; int b• Header File } foo; foo.a = 10;• Preprocessor / macros
  35. 35. 零负担• 不对栈变量自动初始化• Object on Stack• 默认构造函数不对POD类型进行初始化• 成员函数默认为非虚函数
  36. 36. 值语义Person kent("kent"); kent "kent"
  37. 37. 值语义Person kent("kent");Person lazy = kent; kent "kent" lazy "kent"
  38. 38. 引用语义Person kent("kent"); kent "kent"
  39. 39. 引用语义Person kent("kent");Person lazy = kent; kent "kent" lazy
  40. 40. Not very good at OO• No reflection and dynamic creation• Object lifetime management• Complex syntax stops refactoring tools
  41. 41. 既然如此,为什么我们还要用C++
  42. 42. C++ is deterministic
  43. 43. C++ is deterministic• Destructing is determinate - No GC• Performance is predictable - C++ is fast only when coders are experts - Java is almost as fast, much higher productivity
  44. 44. Where the Focus Is Efficiency Flexibility Abstraction Productivity C non-goal non-goal C++ non-goal at the at theJava, C# expense of expense of
  45. 45. Conclusion• There are only two kinds of languages - The ones people always complain about - The ones nobody uses• C++ is an undoubted success• One language doesn’t fit all - Important to known when and when not
  46. 46. 天机亦可泄漏
  47. 47. 对象内存模型
  48. 48. 简单对象class Animal { public: void Run(); private: char* name; int age; char sex;};
  49. 49. 简单对象class Animal { name public: void Run(); private: age char* name; int age; char sex;}; Sex Alignment
  50. 50. 单一继承class Animal { public: void Run(); private: char* name; int age; char sex;};class Lion : public Animal { private: char* address;};
  51. 51. 单一继承class Animal { address public: void Run(); private: name char* name; int age; char sex;}; ageclass Lion : public Animal { private: char* address; Sex Alignment};
  52. 52. 虚函数 class Animal { public: void Run(); virtual void Say(); private: char* name; int age; char sex; };* vptr的偏移量与编译器实现有 .
  53. 53. 虚函数 class Animal { vptr public: void Run(); virtual void Say(); name private: char* name; age int age; char sex; }; Sex Alignment* vptr的偏移量与编译器实现有 .
  54. 54. vptr and vtbl vptr name ageSex Alignment
  55. 55. vptr and vtbl vptr 0 type_info type_info name 1 Say &Animal::Say ageSex Alignment vtbl$Animal
  56. 56. 带虚函数的继承class Animal { public: virtual void Run(); virtual void Say(); private: char* name; int age; char sex;};class Lion { public: virtual void Say();};
  57. 57. 带虚函数的继承class Animal { public: virtual void Run(); virtual void Say(); vptr private: name char* name; int age; char sex; age};class Lion { Sex Alignment public: virtual void Say();};
  58. 58. vptr and vtbl vptr name ageSex Alignment
  59. 59. vptr and vtbl vptr 0 type_info type_info name 1 Run &Animal::Run age 2 Say &Lion::SaySex Alignment vtbl$Lion
  60. 60. M o re• 多重继承• 带虚函数的多重继承• 虚继承• 带虚函数的虚继承• 多重虚继承
  61. 61. 函数转换 class Animal { public: void Run(); private: ... }; Animal a; a.Run();* 真实情况下编译器会对函数名称进行编码,即name mangling.
  62. 62. 函数转换 class Animal { public: void Run(); private: ... }; Animal a; a.Run();* 真实情况下编译器会对函数名称进行编码,即name mangling.
  63. 63. 函数转换 class Animal { void Animal_Run(Animal* this) public: { void Run(); ... } private: ... Animal a; }; Animal_Run(&a); Animal a; a.Run();* 真实情况下编译器会对函数名称进行编码,即name mangling.
  64. 64. 函数转换 class Animal { void Animal_Run(Animal* this) public: { void Run(); ... } private: ... Animal a; }; Animal_Run(&a); Animal a; a.Run();* 真实情况下编译器会对函数名称进行编码,即name mangling.
  65. 65. 虚函数转换class Animal { public: void Run(); virtual void Say(); private: ...};Animal a;a.Say();Animal* p = &a;p->Say();
  66. 66. 虚函数转换class Animal { void Animal_ctor(Animal* this) public: { void Run(); this.vptr = &Animal_vtbl; virtual void Say(); } private: void Animal_Say(Animal* this) ... {}; }Animal a; Animal a;a.Say(); Animal_ctor(&a); Animal_Say(&a);Animal* p = &a; Animal* p = &a;p->Say(); (*(p->vptr[1]))(p);
  67. 67. 虚函数转换class Animal { void Animal_ctor(Animal* this) public: { void Run(); this.vptr = &Animal_vtbl; virtual void Say(); } private: void Animal_Say(Animal* this) ... {}; }Animal a; Animal a;a.Say(); Animal_ctor(&a); Animal_Say(&a);Animal* p = &a; Animal* p = &a;p->Say(); (*(p->vptr[1]))(p);
  68. 68. 函数调用• 对象类型参数传递• 对象类型参数返回• 临时对象• Return Value Optimization
  69. 69. 简单类型函数调用int sum(int a, int b) { int result = a + b; return result;}int main(int argc, char* argv[]){ sum(1, 4); return 0;}* 调用栈与机器架构有 , 这里以x86为例.
  70. 70. 简单类型函数调用 ...int sum(int a, int b) { int result = a + b; 4 return result;} 1int main(int argc, char* argv[]){ sum(1, 4); return 0;}* 调用栈与机器架构有 , 这里以x86为例.
  71. 71. 简单类型函数调用 ...int sum(int a, int b) { int result = a + b; 4 return result;} 1int main(int argc, char* argv[]){ Return Address sum(1, 4); return 0;}* 调用栈与机器架构有 , 这里以x86为例.
  72. 72. 简单类型函数调用 ...int sum(int a, int b) { 5 int result = a + b; eax 4 return result;} 1int main(int argc, char* argv[]){ Return Address sum(1, 4); return 0;} ebp Saved ebp esp sum* 调用栈与机器架构有 , 这里以x86为例.
  73. 73. 类类型参数传递class Money { public: Money Add(Money money); private: uint64_t amount;};Money item(700);Money freight(10);Money total = item.Add(freight);
  74. 74. 类类型参数传递 ...class Money { public: Money Add(Money money); temp - Money(10) private: uint64_t amount;};Money item(700);Money freight(10);Money total = item.Add(freight);
  75. 75. 类类型参数传递 ...class Money { public: Money Add(Money money); temp - Money(10) private: uint64_t amount;}; Return AddressMoney item(700);Money freight(10);Money total = item.Add(freight);
  76. 76. 类类型参数传递 ...class Money { public: Money Add(Money money); temp - Money(10) private: uint64_t amount;}; Return AddressMoney item(700);Money freight(10); ebp Saved ebpMoney total = item.Add(freight); esp sum
  77. 77. 类类型返回值class Money { public: Money Add(Money money); private: uint64_t amount;};Money item(700);Money freight(10);Money total = item.Add(freight);
  78. 78. 类类型返回值class Money { void Money_Add( public: Money* this, Money Add(Money money); Money* ret, Money money) private: { uint64_t amount; Money result = ...;}; *ret = result; }Money item(700); ...Money freight(10); Money temp;Money total = item.Add(freight); Money_Add(&item, &temp, freight); Money total = temp; temp.Money::~Money();
  79. 79. 类类型返回值class Money { void Money_Add( public: Money* this, Money Add(Money money); Money* ret, Money money) private: { uint64_t amount; Money result = ...;}; *ret = result; }Money item(700); ...Money freight(10); Money temp;Money total = item.Add(freight); Money_Add(&item, &temp, freight); Money total = temp; temp.Money::~Money();
  80. 80. 临时对象• 函数调用的参数传递与返回• 额外的对象构造与析构• 额外的对象拷贝• 可能戏剧性的影响程序效率
  81. 81. Tips 2 Prefer pass-by-reference to pass-by-value
  82. 82. Return Value Optimizationvoid Money_Add( Money* this, Money* ret, Money money){ Money result = ...; *ret = result;}Money item(700);Money freight(10);Money temp;Money_Add(&item, &temp, freight);Money total = temp;
  83. 83. Return Value Optimizationvoid Money_Add( void Money_Add( Money* this, Money* this, Money* ret, Money* ret, Money money) Money money){ { Money result = ...; *ret = ...; *ret = result; }} Money item(700);Money item(700); Money freight(10);Money freight(10); Money temp;Money temp; Money total;Money_Add(&item, &temp, freight); Money_Add(&item, &total, freight);Money total = temp;
  84. 84. Return Value Optimizationvoid Money_Add( void Money_Add( Money* this, Money* this, Money* ret, Money* ret, Money money) Money money){ { Money result = ...; *ret = ...; *ret = result; }} Money item(700);Money item(700); Money freight(10);Money freight(10); Money temp;Money temp; Money total;Money_Add(&item, &temp, freight); Money_Add(&item, &total, freight);Money total = temp;
  85. 85. std::string• Implementations - Eager Copy - CoW - Copy on Write - SSO - Small String Optimization
  86. 86. Copy on Write string data : char*
  87. 87. Copy on Write string "hello"data : char* 5 30 1 h e l l o ...
  88. 88. Copy on Write string "hello"data : char* capacity 5 30 1 h e l l o ... size 引用计数 数据区
  89. 89. SSO stringdata : char*size : size_tcapacity : size_tbuffer : char[16]
  90. 90. Small String string "hello"data : char* 0x12345678size : size_tcapacity : size_tbuffer : char[16] 5 h e l l o
  91. 91. Big String"hell ..." h e l l ...0x12345678 20 32
  92. 92. Tips 3 Critically Analyze What You Read And Hear
  93. 93. 静态变量初始化Animal animal("Lion");int Foo() { ...}int num = Foo();
  94. 94. 静态变量初始化Animal animal("Lion"); void __sti_ii() { animal.Animal::Animal();int Foo() { num = Foo(); ... }} void __std_ii() {int num = Foo(); animal.Animal::~Animal(); }
  95. 95. inline vs. iteratorvector<int>::iterator it = vec.begin();vector<int>::iterator end = vec.end(); for (vector<int>::iterator it = vec.begin();for (; it != end; ++it) { it != vec.end(); ++it) {} }
  96. 96. inline vs. iteratorvector<int>::iterator it = vec.begin();vector<int>::iterator end = vec.end(); for (vector<int>::iterator it = vec.begin();for (; it != end; ++it) { it != vec.end(); ++it) { it = vec.erase(it); it = vec.erase(it);} }
  97. 97. inline vs. iteratorvector<int>::iterator it = vec.begin();vector<int>::iterator end = vec.end(); for (vector<int>::iterator it = vec.begin();for (; it != end; ++it) { it != vec.end(); ++it) { it = vec.erase(it); it = vec.erase(it);} }
  98. 98. Tips 4 Dont Assume It, Prove It
  99. 99. Prove I t!• Only Code Never Lies• Assembly Language• g++ - -S• nm
  100. 100. References• Bjarne Stroustrup. 1994. The Design And Evolution of C++• Stanley B. Lippman. 1996. Inside the C++ Object Model• Scott Meyers. 2006. Effective C++• 陈硕. 2012. C++工程实践
  101. 101. Q&A
  102. 102. Thanks for your time

×