《程序员》杂志专家门诊C/C++问题
下面是《程序员》杂志第5期中专家门诊部分的C/C++问题,我整理了几个,大家能否看看有没有什么问题。
由于这次时间仓促,没有及时与大家商量,非常抱歉。以后希望大家多提建议,推荐您认为好的问题,共同学习。
----------------------------------------------
需要在 p = new xxx()之后检查NULL吗?
按现行标准,如果内存分配失败,则会抛出std::bad_alloc异常。但有些编译器仍遵循以前的方式:返回0,例如Microsoft Visual C++。不过从VC7开始,CRT仍采取这样的方式,但VC中的C++标准库则支持抛出异常之一标准方式。详细情况请见MSDN。
另外,标准委员会为了与以前保持一致性,也提供了不抛出异常的方式:
xxx *p = new (nothrow) xxx;
这时就不妨用assert(p)。
相关问题在Effective C++上有非常精彩的描述,请参考。
----------------------------------------------
如何安全地将多态指针放进STL容器?
class A{};
class C: public A{};
// 以vector为例,如果
vector<A*> vec;
vec.push_back(new C());
问题出现如何对容器中的指针进行管理上,假如直接把指针放到容器里,然后在进行删除元素操作和容器的析构器中释放元素指向的内存,听起来似乎井井有条,但是如果一个容器中有多个元素指向同一个对象或者多个指向同一个对象的元素被包含到多个容器中,就会带来一片混乱
。
那么用标准库中的auto_ptr来管理指针又会如何呢?情况可能会更糟,不但老问题不能解决,还带来了新问题,auto_ptr只是简单地将指针的管理权在对象之间转移,假如在对容器进行操作的算法中将元素的管理权交给了临时对象,那么当算法完成后临时对象将自动地释放该元素指向的内存,结果将不堪设想。毕竟,auto_ptr是典型的“一拷就坏(Copy Destructive)”。
有一种解决办法是专门用一个容器来保存所有的动态对象,只有该容器可以删除对象,其他容器只保留指向这些对象的指针。当然这种做法比较烦。另一种简单的方法是利用Boost库(介绍见《程序员》2002年3月号的《走进Boost》一文)中的shared_ptr。
#include <list>
#include <boost/shared_ptr.hpp>
class A{};
class C: public A{};
void g()
{
typedef boost::shared_ptr<A> element_type;
typedef std::list<element_type> list_type;
list_type ll;
ll.push_back(element_type(new C));
}
这个比auto_ptr复杂得多的东东管理的是对象的引用计数,当计数为0时自动释放内存,呵呵,真是个好管家。
----------------------------------------------
一个std::string对象,要把这个对象两端多余的空格去掉,怎么办?
可以利用string的成员函数find_first_not_of和find_last_not_of:
#include <iostream>
#include <string>
template <class T> void trim(std::basic_string<T>& s)
{
const char c = ' ';
s.erase(0, s.find_first_not_of(c));
s.erase(s.find_last_not_of(c) + 1);
}
void main()
{
using namespace std;
string str(" 123 456 789 ");
trim(str);
cout << str << '$' << endl;
return;
}
如果字符串非空部分很长的话,上面的find_last_not_of显然缺乏效率,我们可以把trim函数改写为:
template <class T> void trim(std::basic_string<T>& s)
{
const char c = ' ';
s.erase(0, s.find_first_not_of(c));
basic_string<T>::reverse_iterator i =
std::find_if(s.rbegin(), s.rend(),
std::bind2nd(std::not_equal_to<T>(), c));
s.erase(i.base(), s.end());
}
不知道是否还有更好的方法。
----------------------------------------------