Alo*_*kin 56 c++ boost pointers smart-pointers
在阅读完这个答案后,看起来最好尽可能使用智能指针,并将"普通"/原始指针的使用量降至最低.
真的吗?
Arm*_*yan 82
不,这不是真的.如果一个函数需要一个指针并且与所有权无关,那么我强烈认为应该传递一个常规指针,原因如下:
shared_ptr那么你将无法通过,比方说,scoped_ptr规则就是这样 - 如果你知道一个实体必须对对象拥有某种所有权,那么总是使用智能指针 - 那个能为你提供所需所有权的指针.如果没有所有权的概念,永远不要使用智能指针.
例1:
void PrintObject(shared_ptr<const Object> po) //bad
{
if(po)
po->Print();
else
log_error();
}
void PrintObject(const Object* po) //good
{
if(po)
po->Print();
else
log_error();
}
Run Code Online (Sandbox Code Playgroud)
例2:
Object* createObject() //bad
{
return new Object;
}
some_smart_ptr<Object> createObject() //good
{
return some_smart_ptr<Object>(new Object);
}
Run Code Online (Sandbox Code Playgroud)
Luc*_*ton 14
使用智能指针来管理所有权是正确的做法.相反,在所有权不是问题的地方使用原始指针并没有错.
以下是原始指针的一些完全合法的使用(记住,总是假设它们是非拥有的):
他们与参考竞争的地方
0对象的生命周期std::bind使用一种约定,其中传递的参数被复制到生成的仿函数中; 但是std::bind(&T::some_member, this, ...)只复制指针而std::bind(&T::some_member, *this, ...)复制对象; std::bind(&T::some_member, std::ref(*this), ...)是另一种选择他们不与参考文献竞争的地方
boost::optional<T&>boost::optional<T&>作为提醒,它几乎总是错写一个函数(这不是一个构造函数,或如取得所有权的函数成员),然后再将接受一个智能指针,除非它把它传递给构造(例如,它是正确的std::async,因为语义上它是接近是对std::thread构造函数的调用).如果它是同步的,则不需要智能指针.
回顾一下,这是一个演示上述几种用法的片段.我们正在编写和使用一个类,它将一个仿函数应用于std::vector<int>编写一些输出的每一个元素.
class apply_and_log {
public:
// C++03 exception: it's acceptable to pass by pointer to const
// to avoid apply_and_log(std::cout, std::vector<int>())
// notice that our pointer would be left dangling after call to constructor
// this still adds a requirement on the caller that v != 0 or that we throw on 0
apply_and_log(std::ostream& os, std::vector<int> const* v)
: log(&os)
, data(v)
{}
// C++0x alternative
// also usable for C++03 with requirement on v
apply_and_log(std::ostream& os, std::vector<int> const& v)
: log(&os)
, data(&v)
{}
// now apply_and_log(std::cout, std::vector<int> {}) is invalid in C++0x
// && is also acceptable instead of const&&
apply_and_log(std::ostream& os, std::vector<int> const&&) = delete;
// Notice that without effort copy (also move), assignment and destruction
// are correct.
// Class invariants: member pointers are never 0.
// Requirements on construction: the passed stream and vector must outlive *this
typedef std::function<void(std::vector<int> const&)> callback_type;
// optional callback
// alternative: boost::optional<callback_type&>
void
do_work(callback_type* callback)
{
// for convenience
auto& v = *data;
// using raw pointers as iterators
int* begin = &v[0];
int* end = begin + v.size();
// ...
if(callback) {
callback(v);
}
}
private:
// association: we use a pointer
// notice that the type is polymorphic and non-copyable,
// so composition is not a reasonable option
std::ostream* log;
// association: we use a pointer to const
// contrived example for the constructors
std::vector<int> const* data;
};
Run Code Online (Sandbox Code Playgroud)
始终建议使用智能指针,因为它们清楚地记录了所有权.
然而,我们真正想念的是一个"空白"智能指针,这并不意味着任何所有权概念.
template <typename T>
class ptr // thanks to Martinho for the name suggestion :)
{
public:
ptr(T* p): _p(p) {}
template <typename U> ptr(U* p): _p(p) {}
template <typename SP> ptr(SP const& sp): _p(sp.get()) {}
T& operator*() const { assert(_p); return *_p; }
T* operator->() const { assert(_p); return _p; }
private:
T* _p;
}; // class ptr<T>
Run Code Online (Sandbox Code Playgroud)
实际上,这是可能存在的任何智能指针的最简单版本:一种记录它不拥有它所指向的资源的类型.