Я правильно инициализирую свои контрольные переменные С++?
Я пробовал 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;
}