简体   繁体   English

返回临时引用

[英]returning a reference to temporary

I understand that it's illegal to return a reference to a temporary, but here's my problem: 我知道返回临时引用是违法的,但这是我的问题:

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!
    }
}

The three first three options return a const reference to a stringSet data member. 前三个选项将const引用返回给stringSet数据成员。 What should I do for the default case? 我应该怎么做默认情况? If I leave it out, the compiler (GCC with -Wall -Wextra -pedantic ) complains and I don't want it to because those options tend to catch my bed design choices in the most odd of ways :) 如果我把它留下来,编译器(GCC with -Wall -Wextra -pedantic )抱怨并且我不想要它,因为这些选项倾向于以最奇怪的方式抓住我的床设计选择:)

Thanks! 谢谢!

Keep a default set as a member too... and return a reference to it. 将默认设置保留为成员...并返回对它的引用。 That is of course if the default case is theoretically possible. 当然,如果默认情况在理论上是可行的。 If it is not, throw an exception and don't return anything. 如果不是,抛出异常并且不返回任何内容。

default:
   throw invalid_argument_exception();
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; // <--
    }
}

You can't return a reference to a temporary object you created on the stack. 您不能返回对在堆栈上创建的临时对象的引用。 I'll be destroyed by the time your function returns, and your application will crash. 我的函数返回时会被破坏,你的应用程序会崩溃。

If you intend on doing something like that, you'll have to return by value rather than by reference, ie 如果你打算做那样的事情,你将不得不按价值而不是通过参考来回报,即

stringSet Target::dirList( const dirType type ) const

This can obviously have performance implications since you will very likely end up having the copy constructor getting called for your other references. 这显然会对性能产生影响,因为您很可能最终会为其他引用调用复制构造函数。 The alternative would be to avoid creating a temporary object on the stack. 另一种方法是避免在堆栈上创建临时对象。 Depending on your application, there are several ways you could do it, like having a simple pool that you get your temporary objects from and that are being garbage-collected at some point, or you could have dirList take a stringSet argument that is being populated by your function. 根据您的应用程序,您可以通过多种方式执行此操作,例如使用一个简单的池来获取临时对象,并在某些时候进行垃圾收集,或者您可以让dirList获取正在填充的stringSet参数按你的功能。

Best case - can't you just have a permanent default set somewhere? 最好的情况 - 你不能只在某个地方设置永久默认设置吗? Does it have to be unique per call? 每次通话都必须是唯一的吗?

Not necessarily always the right option, but for what it's worth you can use shared_ptr for this -- construct a shared_ptr with a null deleter and return that if the string set already exists, otherwise construct one pointing to an empty set and having a normal deleter and return that. 不一定总是正确的选项,但是为了它值得你可以使用shared_ptr - 用null删除器构造一个shared_ptr并返回如果字符串集已经存在,否则构造一个指向空集并具有正常删除器并返回。 In other words: 换一种说法:

#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;
}

There are directives you can put in an impossible-case default handler to say that it's unreachable. 有一些指令可以放在一个不可能的案例默认处理程序中,说它无法访问。 Compiler-specific and non-portable, but most compilers have something. 编译器特定和非可移植,但大多数编译器都有。 I just don't remember how GCC spells this. 我只是不记得海湾合作委员会如何拼写这个。

EDIT found the syntax... 编辑找到了语法...

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

As I said, this is a GCC-specific feature - there's a differently-spelled Visual C++ equivalent, though. 正如我所说,这是一个特定于GCC的功能 - 但是有一个不同拼写的Visual C ++等价物。

BTW - there's always return *((stringSet*) 0); BTW - 总是return *((stringSet*) 0); .

EDIT Or throw an exception. 编辑或抛出异常。

Either way (except the exception, maybe), only if you're really sure it will never happen. 无论哪种方式(除了例外,可能),只有你真的确定它永远不会发生。

If I understood you correctly.......... 如果我理解正确..........
Here's how I do it with such switches. 以下是我使用这种开关的方法。
Two notes regarding this code: 关于此代码的两个注释:
1. I hate using "&" ref and prefer the "* const" one (more readable) so please adjust. 1.我讨厌使用“&”引用并更喜欢“* const”(更易读),所以请调整。 It's the same in essence. 它本质上是一样的。
2. Didn't test this code. 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM