4

我喜欢 C++11 中的新指针类型,但有时我仍然需要原始指针。然而,让我对 C++ 中的“原始”类型越来越难过的是,它们习惯于在未给出明确值时初始化为未定义。当我更频繁地使用 std::shared_ptr<> 等时,需要将原始指针初始化为 null 感觉越来越脆弱和不必要。我在谈论:

class foo
{
    ...
    std::shared_ptr< bar > pb;   // Initially null in whatever constructor.
    std::unique_ptr< dar > pd;   // Likewise.
    std::weak_ptr< gar > pg;     // And again.
    lar* pr;                     // Uh-oh! Who knows what this is? Better remember to initialize...
};

foo::foo( int j )
: pr( nullptr )
{...}

foo::foo( const string& s )
: pr( nullptr )
{...}

... etc.: many tedious and error-prone constructor definitions follow.

因此,我想要的是“具有空初始化的原始指针”。就像是:

class foo
{
    ...
    std::shared_ptr< bar > pb;   // Initially null in whatever constructor.
    std::unique_ptr< dar > pd;   // Likewise.
    std::weak_ptr< gar > pg;     // And again.
    raw_ptr< lar > pr;           // Once more with feeling.
};

foo::foo( int j )
{...}                            // No explicit pointer initialization necessary.

foo::foo( const string& s )
{...}

...

更准确地说,我想要的是一种简单、廉价的类型,除了它的默认构造函数将其初始化为 nullptr 之外,它在各方面的行为都与原始指针完全一样。

我的问题:(1)标准库中是否已经存在这样的东西?(2) 如果不是,那么完成这种类型的实现的最优雅/最小的方法是什么?

PS 我对 Boost 或任何其他库不感兴趣,除非它可能是单个文件中的仅标头库。小和简单是本质。

4

4 回答 4

16

C++11 允许在类中初始化数据成员。

class foo
{
  // ...
  lar *pr = nullptr;
};

除非您在构造函数中分配另一个值,否则它将始终初始化pr为。nullptr

于 2013-07-08T19:17:49.487 回答
9

看起来您需要“世界上最笨的智能指针”,它已被提议作为未来 C++ 标准模板库的补充。您可以在此处查看提案:“A Proposal for the World's Dumbest Smart Pointer”和此处: “A Proposal for the World's Dumbest Smart Pointer,v2”和此处:“A Proposal for the World's Dumbest Smart Pointer,v3”

该提案包含一个潜在的部分实现,您可以调整它以与您当前使用的编译器一起使用。该实现类似于 Mark Ransom 提供的 most_raw_ptr 解决方案。网络搜索 exclude_ptr 将提供更多详细信息。

世界上最愚蠢的智能指针的提案,v3 已“将exempt_ptr 重命名为observer_ptr”,请参阅链接文档以了解其他更改。

于 2013-07-08T23:14:35.297 回答
6
template<typename T>
class almost_raw_ptr
{
public:
    almost_raw_ptr(T* p = nullptr) : m_p(p) {}
    T* operator=(T* p) { m_p = p; return p; }
    operator T*() const { return m_p; }
    T* operator->() const { return m_p; }
    T& operator*() const { return *m_p; }
    T& operator[](int i) const { return m_p[i]; }

private:
    T* m_p;
};

如果您需要指针或对实际原始指针的引用,这将不起作用,但它应该适用于其他一切。

于 2013-07-08T19:20:26.137 回答
-2

当您使用原始指针并期望该值0表示该指针尚未初始化时,该值0在某种意义上是“哨兵值”或“魔术饼干”。将魔术 cookie 视为指示状态的特殊值,但在其他方面与该数据类型的正常有效值无法区分。

由于所有常见原因,魔术饼干很糟糕,这可能会触发你的感觉,即它很脆弱,最终不需要。不使用哨兵值的解决方案可能会感觉更好。

一种这样的解决方案是使用boost::optional

typedef Foo* FooPtr;
boost::optional <FooPtr> foo;
// ...
if (!foo)
{
  // the pointer is not yet initialized
} 
else
{
  // the pointer IS initialized
  Foo* theFoo = *foo;
}

初始化指针很简单:

foo = new Foo;

optional不是哨兵值,因为您没有存储特殊值Foo*来指示指针未初始化。唯一的工作就是optional回答“指针是否已初始化?”这个问题时说“是”或“否”。

于 2013-07-08T19:45:41.890 回答