返回临时引用

时间:2010-11-28 20:13:32

标签: c++ reference switch-statement

我知道返回临时引用是违法的,但这是我的问题:

const stringSet & Target::dirList( const dirType type ) const
{
    switch( type )
    {
        case SOURCE_DIR:
            return m_sourceDirs;
        case HEADER_DIR:
            return m_headerDirs;
        case RESOURCE_DIR:
            return m_resourceDirs;
        default:
            return stringSet(); // PROBLEM HERE!
    }
}

前三个选项返回对stringSet数据成员的const引用。我应该怎么做默认情况?如果我把它遗漏,编译器(GCC与-Wall -Wextra -pedantic)抱怨并且我不想要它,因为这些选项倾向于以最奇怪的方式捕捉我的床设计选择:)

谢谢!

6 个答案:

答案 0 :(得分:9)

将默认设置保留为成员...并返回对它的引用。当然,如果默认情况在理论上是可行的。如果不是,则抛出异常而不返回任何内容。

default:
   throw invalid_argument_exception();

答案 1 :(得分:4)

const stringSet & Target::dirList( const dirType type ) const
{
    static const stringSet defaultSet; // <--
    switch( type )
    {
        case SOURCE_DIR:
            return m_sourceDirs;
        case HEADER_DIR:
            return m_headerDirs;
        case RESOURCE_DIR:
            return m_resourceDirs;
        default:
            return defaultSet; // <--
    }
}

答案 2 :(得分:0)

您无法返回对在堆栈上创建的临时对象的引用。我将在你的函数返回时被销毁,你的应用程序将崩溃。

如果您打算做类似的事情,您将不得不按价值而不是通过参考来回报,即

stringSet Target::dirList( const dirType type ) const

这显然会影响性能,因为很可能最终会为其他引用调用复制构造函数。另一种方法是避免在堆栈上创建临时对象。根据您的应用程序,您可以通过多种方式执行此操作,例如使用一个简单的池来获取临时对象,并在某些时候进行垃圾收集,或者您可以让dirList获取正在填充的stringSet参数通过你的功能。

最好的情况 - 你不能只在某个地方设置永久默认设置吗?每次通话都必须是唯一的吗?

答案 3 :(得分:0)

不一定总是正确的选项,但是为了它值得你可以使用shared_ptr - 用null删除器构造一个shared_ptr并返回如果字符串集已经存在,否则构造一个指向空集并且具有正常的删除并返回。换句话说:

#include <set>
#include <string>

#include <boost/shared_ptr.hpp>

struct NullDeleter
{
    void operator()(void *p) {}
};

enum DirType
{
    SOURCE_DIR,
    HEADER_DIR,
    RESOURCE_DIR,
    OTHER,
};

typedef std::set<std::string> StringSet;
typedef boost::shared_ptr<const StringSet> StringSet_CPtr;

struct Target
{
    StringSet m_sourceDirs, m_headerDirs, m_resourceDirs;

    Target()
    {
        m_sourceDirs.insert("/source");
        m_headerDirs.insert("/header");
        m_resourceDirs.insert("/resources");
    }

    StringSet_CPtr dir_list(DirType type)
    {
        switch(type)
        {
        case SOURCE_DIR:
            return StringSet_CPtr(&m_sourceDirs, NullDeleter());
        case HEADER_DIR:
            return StringSet_CPtr(&m_headerDirs, NullDeleter());
        case RESOURCE_DIR:
            return StringSet_CPtr(&m_resourceDirs, NullDeleter());
        default:
            return StringSet_CPtr(new StringSet);
        }
    }
};

int main()
{
    Target t;
    StringSet_CPtr  sourceDirs = t.dir_list(SOURCE_DIR),
                    headerDirs = t.dir_list(HEADER_DIR),
                    resourceDirs = t.dir_list(RESOURCE_DIR),
                    otherDirs = t.dir_list(OTHER);
    return 0;
}

答案 4 :(得分:0)

有一些指令可以放在一个不可能的案例默认处理程序中,说它无法访问。编译器特定和非可移植,但大多数编译器都有。我只是不记得GCC是如何解释的。

编辑找到了语法...

switch (whatever)
{
  case blah :
    ...;
    break;
  default :
    __builtin_unreachable ();
}

正如我所说,这是一个特定于GCC的功能 - 但是有一个不同拼写的Visual C ++等价物。

BTW - 总是return *((stringSet*) 0);

编辑或抛出异常。

无论哪种方式(例外情况除外),只有当你确实确定它永远不会发生时。

答案 5 :(得分:-2)

如果我理解正确..........
以下是我使用这种开关的方法 关于此代码的两个注释:
 我讨厌使用“&amp;” ref并且更喜欢“* const”(更可读),所以请调整。它本质上是一样的。
 2.没有测试此代码。

const stringSet * const
Target::dirList( const dirType type ) const
{
    const stringSet * pRet = NULL;


    switch( type )
    {
        case SOURCE_DIR:
            stringSet = m_sourceDirs;
        case HEADER_DIR:
            stringSet = m_headerDirs;
        case RESOURCE_DIR:
            stringSet = m_resourceDirs;
    }



    return pRet;
}