возвращая ссылку на временный - PullRequest
4 голосов
/ 28 ноября 2010

Я понимаю, что незаконно возвращать ссылку на временный объект, но вот моя проблема:

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 ]

9 голосов
/ 28 ноября 2010

Сохраните набор по умолчанию как член ... и верните ссылку на него. Это, конечно, если случай по умолчанию теоретически возможен. Если это не так, создайте исключение и ничего не возвращайте.

default:
   throw invalid_argument_exception();
4 голосов
/ 28 ноября 2010
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; // <--
    }
}
0 голосов
/ 28 ноября 2010

Существуют директивы, которые вы можете поместить в обработчик по умолчанию для невозможного случая, чтобы сказать, что он недоступен. Специфичный для компилятора и непереносимый, но у большинства компиляторов есть что-то. Я просто не помню, как это говорит GCC.

РЕДАКТИРОВАТЬ найден синтаксис ...

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

Как я уже сказал, это особенность GCC - хотя есть и другой, по-разному написанный эквивалент Visual C ++.

Кстати - всегда есть return *((stringSet*) 0);.

РЕДАКТИРОВАТЬ Или выбросить исключение.

В любом случае (кроме исключения, может быть), только если вы действительно уверены, что этого никогда не произойдет.

0 голосов
/ 28 ноября 2010

Не всегда правильный вариант, но для чего вы можете использовать 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;
}
0 голосов
/ 28 ноября 2010

Если я вас правильно понял ..........
Вот как я это делаю с такими переключателями.
Два примечания относительно этого кода:
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;
}
0 голосов
/ 28 ноября 2010

Вы не можете вернуть ссылку на временный объект, который вы создали в стеке. Я буду уничтожен к тому времени, когда ваша функция вернется, и ваше приложение будет аварийно завершено.

Если вы намерены сделать что-то подобное, вам придется возвращаться по значению, а не по ссылке, т.е.

stringSet Target::dirList( const dirType type ) const

Очевидно, что это может повлиять на производительность, так как вам, скорее всего, придется вызывать конструктор копирования для других ваших ссылок. Альтернативой было бы избежать создания временного объекта в стеке. В зависимости от вашего приложения, вы можете сделать это несколькими способами, например, иметь простой пул, из которого вы получаете временные объекты и в какой-то момент занимающийся сборкой мусора, или вы можете заставить dirList принять заполняемый аргумент stringSet по вашей функции.

В лучшем случае - разве вы не можете просто установить постоянную настройку по умолчанию где-нибудь? Должен ли он быть уникальным для каждого звонка?

...