代码之家  ›  专栏  ›  技术社区  ›  rubenvb

返回临时引用

  •  4
  • rubenvb  · 技术社区  · 15 年前

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

    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 数据成员。对于默认情况我应该怎么做?如果我不写,编译器(gcc -Wall -Wextra -pedantic )我不想抱怨,因为这些选择往往会以最奇怪的方式抓住我的床设计选择:)

    谢谢!

    6 回复  |  直到 15 年前
        1
  •  9
  •   Armen Tsirunyan    15 年前

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

    default:
       throw invalid_argument_exception();
    
        2
  •  4
  •   Peter Alexander    15 年前
    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; // <--
        }
    }
    
        3
  •  0
  •   EboMike    15 年前

    不能返回对在堆栈上创建的临时对象的引用。函数返回时,我将被破坏,您的应用程序将崩溃。

    如果你打算做那样的事情,你必须按价值而不是参照返回,也就是说。

    stringSet Target::dirList( const dirType type ) const

    这显然会影响性能,因为最终很可能会调用复制构造函数来获取其他引用。另一种方法是避免在堆栈上创建临时对象。根据应用程序的不同,有几种方法可以做到这一点,比如拥有一个简单的池,从中获取临时对象,并在某个时刻被垃圾收集,或者可以让dirlist接受一个由函数填充的stringset参数。

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

        4
  •  0
  •   Stuart Golodetz    15 年前

    不一定总是正确的选项,但是为了它的价值,您可以为此使用shared-ptr——用一个空的删除程序构造一个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;
    }
    
        5
  •  0
  •   Steve314    15 年前

    您可以将一些指令放入不可能的case默认处理程序中,以表示它是不可访问的。编译器特定且不可移植,但大多数编译器都有一些功能。我只是不记得GCC是怎么拼写的。

    编辑 找到语法…

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

    正如我所说的,这是一个GCC特定的特性,但是有一个不同的拼写VisualC++的等价物。

    顺便说一句-总是有 return *((stringSet*) 0); .

    编辑 或者抛出异常。

    不管是哪种方式(也许是例外),只有当你 真正地 当然不会发生。

        6
  •  -2
  •   Poni    15 年前

    如果我正确理解你……
    以下是我使用这些开关的方法。
    关于此代码的两个说明:
    1。我不喜欢使用“&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;
    }