Global const string& плохо пахнет для меня, действительно ли это безопасно?

Я просматриваю код коллеги и вижу, что у него есть несколько констант, определенных в глобальной области видимости как:

const string& SomeConstant = "This is some constant text";

Лично для меня это плохо пахнет, потому что ссылка относится к тому, что я предполагаю, является «анонимным» объектом, созданным из заданного массива символов.

Синтаксически это законно (по крайней мере, в VC++ 7) и, кажется, работает, но на самом деле я бы предпочел, чтобы он удалил &, чтобы не было двусмысленности в отношении того, что он делает.

Итак, это ДЕЙСТВИТЕЛЬНО безопасно и законно, и я одержим? Имеет ли создаваемый временный объект гарантированное время жизни? Я всегда предполагал, что анонимные объекты, используемые таким образом, уничтожаются после использования...


Так что мой вопрос также можно было бы обобщить на время жизни анонимного объекта. Определяет ли стандарт время жизни анонимного объекта? Будет ли он иметь такое же время жизни, как и любой другой объект в той же области? Или дается только время жизни выражения?


Кроме того, когда вы делаете это как локальный, он явно имеет другую область действия:

class A
{
    string _str;

public:
    A(const string& str) :
        _str(str)
    {
        cout << "Constructing A(" << _str << ")" << endl;
    }

    ~A()
    {
        cout << "Destructing A(" << _str << ")" << endl;
    }
};

void TestFun()
{
    A("Outer");
    cout << "Hi" << endl;
}

Показывает:

Построение А (внешнее); Разрушение A (Внешний); Привет


person James Michael Hare    schedule 22.06.2009    source источник
comment
Может ли кто-нибудь также ответить, почему предпочтительнее не использовать ссылку?   -  person Triptych    schedule 22.06.2009
comment
Это не так. Вернее, стандарт в основном говорит, что если он глобальный, он имеет в основном идентичную семантику. (То есть, время жизни временного объекта привязано к времени жизни ссылки const, к которой оно привязано, или что-то в этом роде.)   -  person MSN    schedule 22.06.2009
comment
однако в этом случае вы тратите 4 дополнительных байта, не так ли? +4 для справки и место для временной закулисы?   -  person James Michael Hare    schedule 22.06.2009
comment
Пожалуйста, определите, что вы подразумеваете под анонимным объектом. Этого термина нет в стандарте.   -  person Matthew Flaschen    schedule 22.06.2009
comment
По какой причине он сделал ссылку?   -  person sean e    schedule 22.06.2009
comment
под анонимным я подразумеваю создание объекта без имени, как первая строка в TestFun() выше. Есть ли стандартное название для этого?   -  person James Michael Hare    schedule 23.06.2009
comment
Я думаю, его причина была в том, что я сказал ему, когда он передает строку в fxn, он должен передать const-ссылку, чтобы избежать затрат на копирование, и он сделал это со своей const string& для констант (возможно, глобальный поиск-замена сошел с ума? ) и для возвращаемых значений локальных переменных (теперь это ошибка!)   -  person James Michael Hare    schedule 23.06.2009


Ответы (7)


Это совершенно законно. Он не будет уничтожен, пока программа не завершится.

РЕДАКТИРОВАТЬ: Да, гарантировано:

«Все объекты, которые не имеют динамической продолжительности хранения, не имеют продолжительности хранения потока и не являются локальными, имеют продолжительность статического хранения. Хранилище для этих объектов должно длиться в течение всей программы (3.6.2, 3.6.3). "

-- 2008 Рабочий проект, стандарт для языка программирования C++, § 3.7.1 с. 63

Как заметил Мартин, это не весь ответ. Стандартный черновик далее отмечает (§ 12.2, стр. 250-1):

«Временные объекты типа класса создаются в различных контекстах: привязка значения r к ссылке (8.5.3) [...] Даже когда создание временного объекта избегается (12.8), все семантические ограничения должны соблюдаться, как если бы временный объект был создан. [...] Временные объекты уничтожаются как последний шаг в оценке полного выражения (1.9), которое (лексически) содержит точку, где они были созданы. [...] Есть два контекста в котором временные объекты уничтожаются не в конце полного выражения. [...] Второй контекст — это когда ссылка связана с временным. Временное, к которому привязана ссылка, или временное, которое является полный объект подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования ссылки, за исключением случаев, указанных ниже».

Я тестировал в g++, если вам от этого станет лучше. ;)

person Matthew Flaschen    schedule 22.06.2009
comment
Хотя это гарантировано? Я знаю, что так происходит в Visual C++, но я хочу убедиться, что в соответствии со стандартом C++ анонимный объект, созданный таким образом, живет в течение всего времени существования программы. - person James Michael Hare; 22.06.2009
comment
поэтому я предполагаю, что мой реальный вопрос заключается в том, с точки зрения стандарта С++, получают ли анонимные объекты, созданные в области (глобальной и т. д.), ту же область, или анонимные объекты живут только для выражения, в котором они используются? - person James Michael Hare; 22.06.2009
comment
но это анонимно, не так ли? Потому что это ссылка, а не объект. Если бы это была константа, строка SomeConstant = бла-бла-бла; тогда это инициализация объекта, но если это: const string& SomeConstant = blah blah blah; вместо этого: const string& SomeConstant = string(бла-бла-бла); Кажется, что со ссылкой там есть анонимный объект между ними, потому что const char * не может быть назначен ссылке на строку, только строке (через преобразование в строку). - person James Michael Hare; 22.06.2009
comment
но спасибо за стандартную ссылку. Я посмотрю на это. Не пытаюсь ковыряться в гнидах, просто хочется понять, что именно там происходит и почему. - person James Michael Hare; 22.06.2009
comment
Раздел стандарта не применяется. Временное значение, созданное в правой части назначения, имеет статическую продолжительность хранения. Обычно он уничтожается, когда выражение завершено. Единственная причина, по которой он не уничтожается, заключается в том, что он привязан к константе & и, таким образом, продлевает срок его службы. - person Martin York; 22.06.2009
comment
это гарантировано. Да правильно. Это такая же гарантия, как и гарантия, которую дает вам каждый поставщик компилятора, что в их компиляторе нет ошибок - никогда - и он полностью, на 100%, соответствует стандарту безоговорочно. Отбросьте &. Это бессмысленная и плохая практика. - person Roddy; 22.06.2009
comment
Родди, ОП не спрашивает об ошибках компилятора (да, мы все знаем, что их много). Он спрашивает, что предусматривает стандарт. - person Matthew Flaschen; 22.06.2009
comment
Мартин, я добавил раздел о временном сохранении rvalue из-за ссылки. - person Matthew Flaschen; 22.06.2009
comment
В качестве примечания: временные объекты, связанные ссылкой, уничтожаются путем вызова исходного деструктора временного объекта, а не деструктора ограниченной ссылки. Другими словами: если вы привязываете Derived к Base&, срок жизни временного объекта будет продлен до срока жизни Base&, а когда ссылка выйдет за пределы области видимости, будет вызываться ~Derived (независимо от того, есть ли в Base виртуальный деструктор ), поэтому вы можете получить семантику «виртуального деструктора», не имея vtable - person David Rodríguez - dribeas; 23.06.2009
comment
Не имеет прямого отношения к этому, но в старых версиях gcc была ошибка, когда временные файлы были привязаны к локальной статике (gcc.gnu.org/bugzilla/show_bug.cgi?id=20416). Лично я, хотя это и законно, склонен согласиться с тем, что это не очень хороший стиль. Это также, вероятно, занимает больше места, поскольку потенциально реализация ссылки потребует хранения в дополнение к временному. - person Richard Corden; 23.06.2009

Да, это действительно и законно.

const string& SomeConstant = "This is some constant text";

// Is equivalent too:

const string& SomeConstant = std::string("This is some constant text");

Таким образом, вы создаете временный объект.
Этот временный объект привязан к const&, и, таким образом, его время жизни увеличивается до времени жизни переменной, с которой он также связан (т.е. дольше, чем выражение, в котором он был создан).

Это гарантируется стандартом.

Примечание:

Хотя это законно. Я бы не стал его использовать. Самым простым решением было бы преобразовать его в константу std::string.

Использование:

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

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

Дополнительные мысли:

Это, с другой стороны, не пострадает от проблемы:

char const* SomeConstant = "This is some constant text";

И может быть использован в любой момент. Просто мысль.

person Martin York    schedule 22.06.2009
comment
Очень верно, очень верно. Обычно я использую const char * const, если только мне не нужно использовать более тяжелую строку или если я хочу использовать против нее boost или std string fxns. - person James Michael Hare; 23.06.2009

Это может быть законно, но все равно некрасиво. Оставьте ссылку!

const string SomeConstant = "This is some constant text";
person ralphtheninja    schedule 22.06.2009
comment
Это то, к чему я склоняюсь, поскольку в данном случае & ничего не покупает. Но если это законно и официально так, я ненавижу бить его за это. - person James Michael Hare; 22.06.2009
comment
Я бы не стал его за это бить. Если получится, то оставлю. Я думаю, ваше время было бы лучше потратить на его дизайн. - person Rob; 22.06.2009
comment
Я обычно так и делаю, я просто хотел убедиться, что он портативный. Это работает на VC++7, но если это было нестандартно и они изменили его, это могло стать помехой. Однако, если это соответствует стандарту, меня это устраивает. - person James Michael Hare; 22.06.2009
comment
поверьте мне, я не хочу быть код-нацистом, но он делал действительно глупые вещи, такие как возвращение ссылок на локальные переменные из функций, поэтому я пытаюсь убедиться, что это законно, прежде чем я позволю этому скользить. - person James Michael Hare; 22.06.2009
comment
Я думаю, что того факта, что он вызвал все эти дебаты, должно быть достаточно, чтобы убедить вас, что код лучше без ссылки, даже если он законен. Другие, увидев это позже, могут испытывать такое же неловкое чувство по этому поводу и вызвать новую волну споров просто потому, что это необычно. - person markh44; 23.06.2009
comment
согласованный! Если это не очевидно для человека с разумным уровнем опыта, его лучше избегать. - person James Michael Hare; 23.06.2009
comment
Здесь происходит приятное обсуждение, но не думаете ли вы, что оптимизированный указатель кода char будет лучшим вариантом. Можно избежать ненужного вызова конструктора, используя указатель чата вместо строкового объекта. Просто мысль! - person sriks; 23.07.2013

Это так же законно, как и безобразно.

person Gab Royer    schedule 22.06.2009

Законно расширять временную переменную ссылкой const, это используется ScopeGaurd Александреску. превосходное объяснение Херба Саттера, названного кандидатом на "Самое важное const".

При этом этот конкретный случай является злоупотреблением этой функцией C++, и ссылку следует удалить, оставив простой const string.

person Motti    schedule 22.06.2009

Объявление его как const (что означает, что оно не может быть изменено), а затем создание ссылки, что подразумевает, что кто-то может его изменить, по крайней мере, кажется дурным тоном. Плюс, как я уверен, вы понимаете, глобальные переменные ПЛОХО и редко нужны.

person xcramps    schedule 22.06.2009
comment
это не глобальная переменная, это глобальный идентификатор (const). Но это сбор гнид. - person James Michael Hare; 23.06.2009

Хорошо, люди поправьте меня, если я заблужусь, но вот мои выводы, выслушав все ваши превосходные ответы:

A) это синтаксически и логически допустимо, & продлевает время жизни временного/анонимного объекта за пределами уровня выражения до срока действия ссылки. Я проверил это в VC++7 с помощью:

class A { 
    public: A() { cout << "constructing A" << endl; }
    public: ~A() { cout << "destructing A" << endl; }
};

void Foo()
{
    A();
    cout << "Foo" << endl;
}

void Bar()
{
    const A& someA = A();
    cout << "Bar" << endl;
}

int main()
{
    Foo();    // outputs constructing A, destructing A, Foo
    Bar();    // outputs constructing A, Bar, destructing A
    return 0;
}

B) Хотя это законно, это может привести к некоторой путанице в отношении фактического срока службы, и ссылка в этих случаях не дает вам преимущества от объявления ее не ссылкой, поэтому ссылки, вероятно, следует избегать и может даже быть дополнительным пробелом . Поскольку в этом нет никакой пользы, это ненужное запутывание.

Спасибо всем за ответы, это была очень интересная дискуссия. Итак, вкратце: да, это синтаксически законно, нет, это технически не опасно, поскольку срок службы увеличивается, но это ничего не добавляет и может добавить затрат и путаницы, так зачем беспокоиться.

Звучит правильно?

person James Michael Hare    schedule 23.06.2009
comment
Да, теперь ты в курсе. Это законно, безопасно и, вероятно, не является преднамеренным запутыванием. Но вы правы, рефери не нужен. Кроме того, в коде этого поста были небольшие ошибки, поэтому я его отредактировал. - person Matthew Flaschen; 23.06.2009
comment
спасибо за правки, я набирал сокращенную версию кода, чтобы не усложнять :-) - person James Michael Hare; 23.06.2009