回到C ++中的“NULL参考”?(Returning a “NULL reference” in

2019-06-24 01:05发布

在像JavaScript或PHP动态语言,我经常做的功能,如:

function getSomething(name) {
    if (content_[name]) return content_[name];
    return null; // doesn't exist
}

如果存在的话还是我返回一个对象null ,如果不。

什么是在C ++相当于使用引用? 是否有任何一般建议的模式? 我看到有一个一些框架isNull()用于此目的的方法:

SomeResource SomeClass::getSomething(std::string name) {
    if (content_.find(name) != content_.end()) return content_[name];
    SomeResource output; // Create a "null" resource
    return output;
}

然后调用者将检查资源这种方式:

SomeResource r = obj.getSomething("something");
if (!r.isNull()) {
    // OK
} else {
    // NOT OK
}

但是,具备实现这种为每个类魔术方法似乎沉重。 此外,它似乎并不明显,当对象的内部状态应该从“空”被设置为“不空”。

是否有任何替代这种模式? 我已经知道它可以用指针来完成,但我想知道如何/如果它可以与引用来完成。 或者我应该放弃在返回C“空”的对象++,并使用一些C ++ - 特定的模式? 用正确的方法做的任何建议,将不胜感激。

Answer 1:

中引用你不能这样做,因为他们不应该为NULL。 基本上有三种选择,一是使用指针,使用值语义别人。

  1. 随着指针(注意:这需要同时调用者有一个指向它的资源没有得到破坏,也确保调用者知道它并不需要删除的对象):

     SomeResource* SomeClass::getSomething(std::string name) { std::map<std::string, SomeResource>::iterator it = content_.find(name); if (it != content_.end()) return &(*it); return NULL; } 
  2. 使用std::pair一个bool ,表示如果该项目是否有效(注:需要SomeResource具有适当的默认构造函数,而不是建造昂贵的):

     std::pair<SomeResource, bool> SomeClass::getSomething(std::string name) { std::map<std::string, SomeResource>::iterator it = content_.find(name); if (it != content_.end()) return std::make_pair(*it, true); return std::make_pair(SomeResource(), false); } 
  3. 使用boost::optional

     boost::optional<SomeResource> SomeClass::getSomething(std::string name) { std::map<std::string, SomeResource>::iterator it = content_.find(name); if (it != content_.end()) return *it; return boost::optional<SomeResource>(); } 

如果你想值语义,必须使用升压的能力,我建议第三个选项。 的主要优点boost::optionalstd::pair是一个未初始化boost::optional值不构造类型其包封。 这意味着它适用于那些没有默认构造函数的类型,并节省了时间/内存类型有一个不平凡的默认构造函数。

我还修改您的例子所以你不(通过重新使用迭代器),搜索地图的两倍。



Answer 2:

为什么“除了使用指针”? 使用指针你做的在C ++的方式。 除非你确定它有类似的一些“可选”类型isNull()你提到的功能。 (或使用现有的,像boost::optional

参考设计,并保证, 永远不会是空的 。 问:“让我怎么让他们空”是荒谬的。 您可以使用指针,当你需要一个“可空引用”。



Answer 3:

一个很好的和相对非侵入性的方法,如果实施为各类特殊的方法避免了问题,是与使用boost.optional 。 它本质上是一个模板的包装,它允许你检查所保存的值是否为“有效”与否。

顺便说一句,我认为这是在文档很好的解释,但要注意boost::optionalbool ,这是一个建筑,这是很难解释的。

编辑 :问题询问有关“空引用”,但代码段中,通过返回值的函数。 如果确实函数返回一个参考:

const someResource& getSomething(const std::string& name) const ; // and possibly non-const version

那么函数只会使有道理的,如果someResource到过一辈子至少只要在返回的参考对象的(否则你竟被dhave悬空参考)被提及。 在这种情况下,它似乎完全没有返回一个指针:

const someResource* getSomething(const std::string& name) const; // and possibly non-const version

但你必须绝对清楚的是,来电者不带指针的所有权,不应该试图将其删除。



Answer 4:

I can think of a few ways to handle this:

  • As others suggested, use boost::optional
  • Make the object have a state that indicates it is not valid (Yuk!)
  • Use pointer instead of reference
  • Have a special instance of the class that is the null object
  • Throw an exception to indicate failure (not always applicable)


Answer 5:

不像Java和C#在C ++参考对象不能为空。
所以我会建议两种方法我在这种情况下使用。

1 - 代替参考用型具有一个空比如std :: shared_ptr的

2 - 获得参考的外部参数和返回成功布尔。

bool SomeClass::getSomething(std::string name, SomeResource& outParam) {
    if (content_.find(name) != content_.end()) 
    {
        outParam = content_[name];
        return true;
    }
    return false;
}


Answer 6:

这里有几个想法:

选择1:

class Nullable
{
private:
    bool m_bIsNull;

protected:
    Nullable(bool bIsNull) : m_bIsNull(bIsNull) {}
    void setNull(bool bIsNull) { m_bIsNull = bIsNull; }

public:
    bool isNull();
};

class SomeResource : public Nullable
{
public:
    SomeResource() : Nullable(true) {}
    SomeResource(...) : Nullable(false) { ... }

    ...
};

方案2:

template<class T>
struct Nullable<T>
{
    Nullable(const T& value_) : value(value_), isNull(false) {}
    Nullable() : isNull(true) {}

    T value;
    bool isNull;
};


Answer 7:

下面这段代码演示了如何返回“无效”的引用; 它是使用指针(常规方法)的只是以不同的方式。

不建议您在将被他人使用的代码使用,因为预期是,返回引用函数总是返回有效的引用。

#include <iostream>
#include <cstddef>

#define Nothing(Type) *(Type*)nullptr
//#define Nothing(Type) *(Type*)0

struct A { int i; };
struct B
{
    A a[5];
    B() { for (int i=0;i<5;i++) a[i].i=i+1; }
    A& GetA(int n)
    {
        if ((n>=0)&&(n<5)) return a[n];
        else return Nothing(A);
    }
};

int main()
{
    B b;
    for (int i=3;i<7;i++)
    {
        A &ra=b.GetA(i);
        if (!&ra) std::cout << i << ": ra=nothing\n";
        else std::cout << i << ": ra=" << ra.i << "\n";
    }
    return 0;
}

Nothing(Type)返回一个 ,在这种情况下,通过代表nullptr -你可以如用0 ,到参考的地址设置。 因为,如果你使用指针被这个地址现在可以进行检查。



文章来源: Returning a “NULL reference” in C++?