我发现智能指针比原始指针舒服得多。所以,总是使用智能指针是个好主意吗?(请注意,我来自Java背景,因此不太喜欢显式内存管理的想法。因此,除非智能指针存在严重的性能问题,否则我想继续使用它们。)
注意:虽然我来自Java背景,但我很好地理解了智能指针的实现和RAII的概念。所以当你发帖的时候,你可以从我这一边想当然地看待这个知识。我几乎在任何地方都使用静态分配,只有在必要时才使用指针。我的问题仅仅是:,我可以总是使用智能指针来代替原始指针吗?
发布于 2010-03-16 14:56:34
鉴于这几个编辑,我的印象是,一份全面的摘要是有用的。
1.什么时候不去
在两种情况下,您不应该使用智能指针。
第一种情况是,实际上您不应该使用C++类。IE:如果不向客户端提供源代码,则为DLL边界。说说轶事吧。
第二种情况发生得更频繁:智能管理器意味着所有权。您可以使用指针来指向现有资源,而不需要管理它们的生存期,例如:
void notowner(const std::string& name)
{
Class* pointer(0);
if (name == "cat")
pointer = getCat();
else if (name == "dog")
pointer = getDog();
if (pointer) doSomething(*pointer);
}此示例受到限制。但是指针在语义上不同于引用,因为它可能指向无效位置(空指针)。在这种情况下,不使用智能指针是非常好的,因为您不想管理对象的生存期。
2.智能经理
除非您正在编写智能管理器类,否则如果您使用关键字delete,您正在做一些错误的事情。
这是一个有争议的观点,但是在回顾了这么多有缺陷的代码示例之后,我不再冒险了。因此,如果编写new,就需要为新分配的内存设置一个智能管理器。你现在就需要它。
这并不意味着你不是一个程序员!相反,重用已经证明有效的代码,而不是一遍又一遍地重新发明轮子,这是一项关键技能。
现在,真正的困难开始了:哪个聪明的经理?
3.智能指针
有各种各样的智能指针,具有不同的特点。
跳过通常应该避免的std::auto_ptr (它的复制语义被搞砸了)。
scoped_ptr:没有开销,不能复制或移动。unique_ptr:没有开销,不能复制,可以移动。shared_ptr / weak_ptr:一些开销(引用计数),可以复制。通常,尝试使用scoped_ptr或unique_ptr。如果你需要几个业主尝试改变设计。如果您无法更改设计,并且确实需要几个所有者,请使用shared_ptr,但要注意使用weak_ptr应该打破的引用周期。
4.智能容器
许多智能指针是不打算复制的,因此它们在STL容器中的使用会受到一定程度的影响。
不要求助于shared_ptr及其开销,而是使用来自Boost指针容器的智能容器。它们模仿经典STL容器的接口,但存储它们自己的指针。
5.滚动您自己的
在某些情况下,您可能希望使用自己的智能经理。请检查一下,您并没有错过您预先使用的库中的一些功能。
在出现异常的情况下编写一个聪明的经理是相当困难的。您通常不能假设内存是可用的(new可能失败),或者Copy Constructor具有no throw保证。
在某种程度上可以接受的是,忽略std::bad_alloc异常并强制规定许多帮助者的Copy Constructor不会失败.毕竟,这就是boost::shared_ptr对其删除D模板参数所做的工作。
但我不推荐它,特别是对于初学者。这是一个棘手的问题,而且您现在不太可能注意到这些bug。
6.示例
// For the sake of short code, avoid in real code ;)
using namespace boost;
// Example classes
// Yes, clone returns a raw pointer...
// it puts the burden on the caller as for how to wrap it
// It is to obey the `Cloneable` concept as described in
// the Boost Pointer Container library linked above
struct Cloneable
{
virtual ~Cloneable() {}
virtual Cloneable* clone() const = 0;
};
struct Derived: Cloneable
{
virtual Derived* clone() const { new Derived(*this); }
};
void scoped()
{
scoped_ptr<Cloneable> c(new Derived);
} // memory freed here
// illustration of the moved semantics
unique_ptr<Cloneable> unique()
{
return unique_ptr<Cloneable>(new Derived);
}
void shared()
{
shared_ptr<Cloneable> n1(new Derived);
weak_ptr<Cloneable> w = n1;
{
shared_ptr<Cloneable> n2 = n1; // copy
n1.reset();
assert(n1.get() == 0);
assert(n2.get() != 0);
assert(!w.expired() && w.get() != 0);
} // n2 goes out of scope, the memory is released
assert(w.expired()); // no object any longer
}
void container()
{
ptr_vector<Cloneable> vec;
vec.push_back(new Derived);
vec.push_back(new Derived);
vec.push_back(
vec.front().clone() // Interesting semantic, it is dereferenced!
);
} // when vec goes out of scope, it clears up everything ;)发布于 2010-03-16 12:31:09
智能指针确实执行显式内存管理,如果您不理解它们是如何实现的,那么使用C++编程就会陷入麻烦的境地。记住,记忆并不是他们管理的唯一资源。
但是要回答你的问题,你应该选择智能指针作为解决方案的第一近似值,但可能会在必要时放弃它们。当可以避免指针(或任何类型)或动态分配时,您不应该使用它。例如:
string * s1 = new string( "foo" ); // bad
string s2( "bar" ); // good编辑:回答您的基本问题:“我可以总是使用智能指针来代替原始指针吗??那么,不行。如果您需要实现自己版本的运算符new,就必须让它返回一个指针,而不是智能指针。
发布于 2010-03-16 12:33:12
通常,如果不需要指针,就不应该使用指针(智能的或其他的)。最好是使局部变量、类成员、向量元素和类似项成为普通对象,而不是指向对象的指针。(由于您来自Java,所以可能会尝试使用new分配所有东西,这是不推荐的。)
这种方法("雷伊")大部分时间都可以避免对指针的担忧。
当您必须使用指针时,这取决于具体情况以及为什么需要指针,但通常可以使用智能指针。可能不是总是(粗体)是最好的选择,但这取决于具体情况。
https://stackoverflow.com/questions/2454214
复制相似问题