聊聊C++临时对象的析构时间点------顺便再次提醒大家谨慎使用string的c_str方法

       C++临时对象的析构?这不是很简单么?其实没那么简单。 我们先看看如下程序吧:

 

#include <iostream>
#include <string>
using namespace std;

string test()
{
	return "abc";
}

int main()
{
	const char *p = test().c_str();
	cout << p << endl;

	return 0;
}

        你可能迫切地期待结果为:abc, 其实不然。 为了简便起见, 我们简化一下上述程序:

 

 

#include <iostream>
#include <string>
using namespace std;

int main()
{
	const char *p = string("abc").c_str();
	cout << p << endl;

	return 0;
}

       注意, 结果不是abc. 为什么呢? 我先直接说吧:string("abc")是一个临时对象, 在执行完const char *p = string("abc").c_str();这个语句后, 临时对象就析构了, 也就是说p指向的区域中的值变了。 所以, 结果自然不是abc.

 

 

       这就引出了如下问题: 临时对象是何时析构的呢? 我们先看一个程序:

 

#include <iostream>
#include <string>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A constructor" << endl;
	}

	~A()
	{
		cout << "A destructor" << endl;
	}
};

int main()
{
	A(); // 临时对象

	printf("end xxx\n");
	printf("end yyy\n");

	return 0;
}

      稍微懂一点C++的人会说, 结果是:

 

A constructor
end xxx
end yyy
A destructor

      其实, 上述结果是错误的, 真正的结果是:

A constructor
A destructor
end xxx
end yyy

     

       看来, 在执行完第一个语句后, 临时对象A()就析构了, 我们来看看汇编, 验证一下吧:

        我们看到, 临时对象确实是在printf之前析构的。

 

        好, 我们接着看:

 

#include <iostream>
#include <string>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A constructor" << endl;
	}

	~A()
	{
		cout << "A destructor" << endl;
	}
};

int main()
{
	A(), // 注意, 是逗号运算符
	printf("end xxx\n");
	printf("end yyy\n");

	return 0;
}

      运行结果为:

 

A constructor
end xxx
A destructor
end yyy


      不要惊讶, 查看汇编代码就知道, 临时对象是在 printf("end xxx\n");后析构的。

 

      继续看代码:

 

#include <iostream>
#include <string>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A constructor" << endl;
	}

	~A()
	{
		cout << "A destructor" << endl;
	}
};

int main()
{
	A(), // 注意, 是逗号运算符
	printf("end xxx\n"), // 注意, 是逗号运算符
	printf("end yyy\n");

	return 0;
}

      运行结果为:

 

A constructor
end xxx
end yyy
A destructor

       不要惊讶, 查看汇编代码就知道, 临时对象是在 printf("end xxx\n");后析构的。

 

       由此可见, 临时对象是在遇到其后的第一个分号(语句结束处)析构的。

 

        好, 我们再看看:

 

#include <iostream>
#include <string>
using namespace std;

int main()
{
	const char *p = string("abc").c_str(); // 临时对象在执行完该句后析构了
	cout << p << endl; // 此时p指向垃圾值

	return 0;
}

       一切一目了然。

 

 

       大家在使用临时对象的时候要留个心眼, 尤其是使用string的c_str时, 一旦出错, 经常排查半天, 最后才发现栽倒在此处。 鉴于容易出错, 最后, 我们再看一眼吧:

 

#include <iostream>
#include <string>
using namespace std;

int main()
{
	const char *p = (string("abc") + string("def")).c_str(); // 临时对象在执行完该句后析构了
	cout << p << endl; // 此时p指向垃圾值

	return 0;
}


      OK,  本文先到此为止。

 

 

       备注: 在上面的程序中, 我使用的编译器是VC++6.0, 后来网友“时光”提醒我, g++的编译器会有不同的表现。 在此, 感谢“时光”得意。 另外, 为了写出高质量的可移植代码, 仍需要注意避免使用临时string对象的c_str方法。

 

 

  • 22
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 29
    评论
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值