Я правильно инициализирую свои контрольные переменные С++?

Я пробовал Google эту проблему, и я не могу найти ничего, что я считаю релевантным. Поэтому я должен искать неправильную вещь; тем не менее, я был бы признателен за некоторые советы...

Foobar &foobar = *new Foobar(someArg, anotherArg);

Это только я или это кажется вонючим?

Я понимаю, что ключевое слово new предназначено для использования с указателями (как таковыми):

Foobar *foobar = new Foobar(someArg, anotherArg);

Но что, если вам не требуется указатель на этот экземпляр, и вы хотите использовать ссылку вместо этого? Или, в этом случае вам не нужно явно инициализировать его (подобно локальным переменным); и если это так, что делать, если я хочу инициализировать параметры?

Не работает (если я не делаю что-то неправильно):

// the last argument is of type: int
Foobar &foobar(someArg, anotherArg);

... дает ошибку компилятора:

список выражений инициализатора, обработанный как составное выражение     недействительная инициализация неконстантной ссылки типа Foobar &     из временного типа 'int

А также это не работает:

Foobar &foobar = Foobar(someArg, anotherArg);

... дает ошибку компилятора:

ошибка: неверная инициализация неконстантной ссылки типа     "Foobar & от временного типа Foobar

Обновление 1:

Упомяните, что я возвращаю это значение, поэтому я не хочу использовать локальную переменную; Я хочу использовать значение в куче, а не в стеке:

Foobar &helloWorld()
{
    Foobar &foobar = *new Foobar(someArg, anotherArg);
    foobar.HelloWorld();
    return foobar;
}

Должен ли я использовать указатели вместо этого, или это полностью допустимо?

Ответ 1

Почему вы думаете, что вам нужно использовать новые и ссылки вообще? Почему бы и нет:

Foobar foobar(someArg, anotherArg);

Для вашей функции - верните значение:

Foobar helloWorld()
{
    Foobar foobar(someArg, anotherArg);
    foobar.HelloWorld();
    return foobar;
}

или указатель:

Foobar * helloWorld()
{
    Foobar * foobar = new Foobar(someArg, anotherArg);
    foobar->HelloWorld();
    return foobar;
}

Если вы это сделаете - вызывающий отвечает за удаление выделенного объекта в какой-то момент.

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

Ответ 2

Да, это вонючий!

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

Вы можете сделать...

const Foobar &foobar = Foobar(someArg, anotherArg);

... если вы действительно хотите ссылку. Обратите внимание, что когда foobar выходит из сферы действия, временный объект, на который он ссылается, умрет. Но в этом нет особого смысла писать, когда вы можете прямо писать:

Foobar foobar(someArg, anotherArg);

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

Ответ 3

Ссылки на С++ действительно не так сильны, как люди ожидают их, я думаю, что путаница исходит от людей, которые привыкли к таким языкам, как Java и С#, которые не имеют указателей и имеют ссылки, которые можно переназначить и использовать.

Ссылка на С++ обычно лучше всего используется как псевдоним для переменной, поэтому вы можете упростить такие вещи, как значения передачи и возврата параметров. Есть очень мало ситуаций, когда вы попытаетесь получить ссылку так, как вы делаете в первой строке. Поэтому обычно вам не нужно делать то, что кажется, что вы пытаетесь сделать:)

Вторая строка, конечно, правильная, и вы можете сделать что-то вроде return * foobar из функции, которая возвращает ссылку.

Ответ 4

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

Вы должны проверить GotW на хорошие практики, проходящие вокруг http://www.gotw.ca/gotw/ Я не помню, какой урок он был (было больше одного) но чтение через это более ценно, чем кто-либо понимает (gotchas будет менее неожиданным)

Вы должны попробовать написать код, который НИКОГДА не будет использовать указатели. Я делаю это, но однажды застрял, когда мне нужен контейнер BaseObj. Об этом не было. Обычно я использовал контейнеры STL и имел большинство переменных в стеке {MyClass myVar;...} или как член и передавать его по мере необходимости.

Его тихий легко удалить указатели, как только вы начнете передавать ссылку вместо указателей и используйте stl-контейнеры вместо нового. Обратите внимание, что я никогда не использую auto_ptr. вектор, строка, дека, список и карта должны делать большую часть того, что вам нужно. Существуют и другие контейнеры.

Ответ 5

Нет, у вас это есть. A foo & "указывает на" фактический объект ", поэтому, если вам действительно нужна ссылка foo, вы должны разыменовать указатель foo.

@Neil имеет точку, хотя - синтаксически, как вы получаете то, что хотите, но зачем вам это нужно?

Ответ 6

Я бы рекомендовал использовать интеллектуальный указатель. Вам нужно управлять собственностью, и ссылка не сделает этого для вас. На самом деле, это заслонит вызывающего, что есть какая-либо проблема собственности. Как отметил Скотт Лангхам в комментарии, std:: auto_ptr будет работать. Использование shared_ptr из Boost или TR1 может быть лучшей идеей.

boost::shared_ptr<Foobar> helloWorld()
{
    boost::shared_ptr<Foobar> foobar(new Foobar(someArg, anotherArg));
    foobar->HelloWorld();
    return foobar;
}