中午同事考了一个问题,其实很简单,但一时间没看出来,仔细回味,发现有点味道。
代码如下
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 int main()
7 {
8 const char * pCArray = string("hello").c_str();
9 cout << pCArray << endl;
10 return 0;
11 }
2 #include <string>
3
4 using namespace std;
5
6 int main()
7 {
8 const char * pCArray = string("hello").c_str();
9 cout << pCArray << endl;
10 return 0;
11 }
问这样的做法是否有问题?
其实是有问题的,这里涉及到两个关于生命期的问题:
1. string对象的c_str()方法,返回的C型字符串(以\0结尾的字符数组),其生命期是由该对象维护的。
2. 在第8行的表达式中,string("hello")是一个临时对象,而该临时对象的生命期,在赋值语句执行完后就已经结束了。
因此,在第九行pCArray指向的那块区域,已经是个无效的内存区域,这样的做法是错误的,也是危险的。
基本功就在于对于小概念的牢固掌握啊!
附:C++ 临时对象的生命周期
有关临时对象的生命周期有三种情况:
1)一般情况:临时性对象的被摧毁,应该是对完整表达式(full-expression)求值过程中的最后一个步骤。该完整表达式造成临时对象的产生。
例:
1 #include <iostream>
2 using namespace std;
3 class A
4 {
5 public:
6 A(int i): m_i(i)
7 { cout << "A(): " << m_i << endl;
8 }
9 ~A()
10 { cout << "~A(): " << m_i << endl;
11 }
12 A operator+(const A& rhs)
13 { cout << "A operator+(const A& rhs)" << endl;
14 return A(m_i + rhs.m_i);
15 }
16 int m_i;
17 };
18 int main()
19 { A a1(1), a2(2);
20 a1 + a2;
21 cout << "------------------------------------" << endl;
22 //运行到这里,a1 + a2产生的临时变量已经被释放
23 return 0;
24 }
2 using namespace std;
3 class A
4 {
5 public:
6 A(int i): m_i(i)
7 { cout << "A(): " << m_i << endl;
8 }
9 ~A()
10 { cout << "~A(): " << m_i << endl;
11 }
12 A operator+(const A& rhs)
13 { cout << "A operator+(const A& rhs)" << endl;
14 return A(m_i + rhs.m_i);
15 }
16 int m_i;
17 };
18 int main()
19 { A a1(1), a2(2);
20 a1 + a2;
21 cout << "------------------------------------" << endl;
22 //运行到这里,a1 + a2产生的临时变量已经被释放
23 return 0;
24 }
2)凡含有表达式执行结果的临时性对象,应该存留到object的初始化操作完成为止。
例:
1 #include <iostream>
2 using namespace std;
3 class A
4 {
5 public:
6 A(int i = 0): m_i(i)
7 { cout << "A(): " << m_i << endl;
8 }
9 ~A()
10 { cout << "~A(): " << m_i << endl;
11 }
12 A operator+(const A& rhs)
13 { cout << "A operator+(const A& rhs)" << endl;
14 return A(m_i + rhs.m_i);
15 }
16 A& operator=(const A& rhs)
17 { cout << "A& operator=(const A& rhs)" << endl;
18 m_i += rhs.m_i;
19 return *this;
20 }
21 int m_i;
22 };
23 int main()
24 { A a1(1), a2(2);
25 A a3;
26 a3 = a1 + a2;
27 //a1 + a2产生的临时变量在a3的赋值操作完成后,才释放
28 return 0;
29 }
2 using namespace std;
3 class A
4 {
5 public:
6 A(int i = 0): m_i(i)
7 { cout << "A(): " << m_i << endl;
8 }
9 ~A()
10 { cout << "~A(): " << m_i << endl;
11 }
12 A operator+(const A& rhs)
13 { cout << "A operator+(const A& rhs)" << endl;
14 return A(m_i + rhs.m_i);
15 }
16 A& operator=(const A& rhs)
17 { cout << "A& operator=(const A& rhs)" << endl;
18 m_i += rhs.m_i;
19 return *this;
20 }
21 int m_i;
22 };
23 int main()
24 { A a1(1), a2(2);
25 A a3;
26 a3 = a1 + a2;
27 //a1 + a2产生的临时变量在a3的赋值操作完成后,才释放
28 return 0;
29 }
3)如果一个临时性对象被绑定于一个reference,对象将残留,直到被初始化之reference的生命结束,或直到临时对象的生命范畴(scope)结束——视哪一种情况先到达而定。
例:
1 #include <iostream>
2 using namespace std;
3 class A
4 { friend ostream& operator<<(ostream& os, const A&);
5 public:
6 A()
7 {
8 }
9 A(const A&)
10 { cout << "A(const A&)" << endl;
11 }
12 ~A()
13 { cout << "~A()" << endl;
14 }
15 };
16 ostream& operator<<(ostream& os, const A&)
17 { os << "ostream& operator<<(ostream& os, const A&)" << endl;
18 return os;
19 }
20 const A& f(const A& a)
21 { return a;
22 }
23 int main(int argc, char* argv[])
24 {
25 { const A& a = A();
26 cout << "-------------------" << endl;
27 }
28 //直到被初始化之reference的生命结束
29 cout << f(A()) << endl;
30 //直到临时对象的生命范畴(scope)结束:
31 //临时对象的const引用在f的参数上(而不是返回值)。
32 //这个引用在f()返回的时候就结束了,但是临时对象未必销毁。
33 cout << "-------------------" << endl;
34 return 0;
35 }
2 using namespace std;
3 class A
4 { friend ostream& operator<<(ostream& os, const A&);
5 public:
6 A()
7 {
8 }
9 A(const A&)
10 { cout << "A(const A&)" << endl;
11 }
12 ~A()
13 { cout << "~A()" << endl;
14 }
15 };
16 ostream& operator<<(ostream& os, const A&)
17 { os << "ostream& operator<<(ostream& os, const A&)" << endl;
18 return os;
19 }
20 const A& f(const A& a)
21 { return a;
22 }
23 int main(int argc, char* argv[])
24 {
25 { const A& a = A();
26 cout << "-------------------" << endl;
27 }
28 //直到被初始化之reference的生命结束
29 cout << f(A()) << endl;
30 //直到临时对象的生命范畴(scope)结束:
31 //临时对象的const引用在f的参数上(而不是返回值)。
32 //这个引用在f()返回的时候就结束了,但是临时对象未必销毁。
33 cout << "-------------------" << endl;
34 return 0;
35 }