Правильно ли я инициализирую свои ссылочные переменные C ++? - PullRequest
16 голосов
/ 15 апреля 2009

Я пытался решить эту проблему в 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;
}

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

Ответы [ 6 ]

11 голосов
/ 15 апреля 2009

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

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

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

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

5 голосов
/ 15 апреля 2009

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

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

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

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

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

Foobar foobar(someArg, anotherArg);

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

3 голосов
/ 15 апреля 2009

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

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

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

2 голосов
/ 15 апреля 2009

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

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

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

Это тихо, легко удалить указатели, как только вы начнете передавать ссылку вместо указателей и использовать контейнеры stl вместо новых. Обратите внимание, что я никогда не использую auto_ptr. vector, string, deque, list и map должны делать большую часть того, что вам нужно. Есть другие контейнеры.

1 голос
/ 15 апреля 2009

Я бы рекомендовал использовать умный указатель. Вы должны управлять собственностью, и ссылка не сделает этого за вас. На самом деле, для вызывающего абонента будет неясно, есть ли какие-либо проблемы с собственностью. Как отметил Скотт Лэнгхэм в комментарии, 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;
}
1 голос
/ 15 апреля 2009

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

@ Нейл имеет смысл, хотя - синтаксически это то, как вы получаете то, что вы хотите, но почему вы этого хотите?

...