Временные объекты, переданные в функции, считаются постоянными? - PullRequest
2 голосов
/ 27 марта 2020

Я сделал аргумент функции const & потому что я хочу иметь возможность передавать ей "строковые литералы". Однако мне интересно, возможно ли изменить ссылку, что-то вроде этого:

void addObjectToDictionary(int* obj, const std::string& name)
{
     for (int = 0; i < 10; ++i)
     {
           if (/*Name already exists in dictionary*/)
                name = "object" + std::to_string(rand());
           else { /*Add obj to dictionary*/; return; }
     }
}

int main()
{
     addObjectToDictionary(new int(6), "somename");
)

Мне интересно, является ли удаление констант по ссылке std :: string неопределенным. Другой ответ на этом сайте гласит:

const_cast безопасен, только если вы приводите переменную, которая изначально была неконстантной. Например, если у вас есть функция, которая принимает параметр const char *, и вы передаете модифицируемый char *, можно const_cast вернуть этот параметр обратно в char * и изменить его.

Однако я просто хотел бы знать, считается ли временный объект std :: string, созданный при вызове функции, постоянным или нет.

Ответы [ 2 ]

3 голосов
/ 27 марта 2020

Я сделал аргумент функции const и потому что я хочу иметь возможность передавать ей "строковые литералы".

Если вам интересно, точный тип строковый литерал, подобный этому ...

"string literal"

... is const char[15]. Так уж получилось, что std::string имеет конструктор, который принимает const char*, который const char[15] автоматически распадается, поэтому строковый литерал привязывается к параметру const std::string&.

(const char[15]) --> decay --> (const char*) --> bind --> std::string::string( const char* )

Это создает временный std::string, который содержит копию строкового литерала. Ваша функция затем принимает этот временный std::string как const std::string&. Исходный временный код на самом деле не const Является или нет первоначальный временный символ const явно слабым в стандарте, но равен const в C ++ 17, согласно другому ответу.

Однако мне интересно, можно ли изменить ссылку

Мне интересно, можно ли отбросить const на std :: string ссылка не определена.

Если вы хотите изменить временную, нет необходимости в const_cast. Этот язык дает вам возможность привязываться к временным организациям не const: ссылка rvalue.

// this is a const lvalue reference
// it binds to temporaries
void addObjectToDictionary(int* obj, const std::string& name);

// this is an rvalue reference
// it also binds to temporaries, and will bind to temporaries instead of a
// const lvalue reference if both overloads exist
void addObjectToDictionary(int* obj, std::string&& name);

Ответ на заданный вами вопрос ...

Я просто хотел бы знать, однако, является ли временный объект std :: string, созданный при вызове функции, постоянным или нет.

... равен нет, временные не const очевидно да для C ++ 17 согласно другому ответу. Тем не менее, y Вы также не должны брать временную ссылку const lvalue и отбрасывать const, потому что эта подпись также связывается с фактически const объектами. Вместо этого вы можете привязать временное значение не const, используя ссылочный параметр rvalue.

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

// this templates functions that bind to the exact type of any string literal
template<std::size_t N>
void addObjectToDictionary(int* obj, const char ( &name )[N] );

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

РЕДАКТИРОВАТЬ

В комментариях есть предложение принять строку по значению (std::string, без ссылки). Это также совершенно правильный способ «погрузить» строку в вашу функцию.

// this will bind to string literals without creating a temporary
void addObjectToDictionary(int* obj, std::string name);

То, что происходит здесь, немного по-другому. При передаче строкового литерала параметру const std::string& вы получаете ссылку const на временный std::string. При передаче строкового литерала в простое старое значение std::string то, что раньше было временным, теперь является вашим собственным объектом std::string значения, как вы, * sh, созданным из строкового литерала.

2 голосов
/ 27 марта 2020

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

Что касается вашего вопроса о том, является ли временное значение const в вашем случае: ответ кажется "да". Было много сообщений о дефектах, касающихся формулировки справочной инициализации для каждой из версий стандарта C ++, поэтому я просто расскажу здесь о формулировке C ++ 17. Соответствующим положением в стандарте является [dcl.init.ref] /5.2.2.1:

Если T1 или T2 является типом класса и T1 не связан со ссылкой T2, пользовательские преобразования рассматриваются с использованием правил инициализации копирования объекта типа « cv1 T1» путем пользовательского преобразования (11.6, 16.3.1.4, 16.3.1.5) ; программа некорректна, если соответствующая нереферентная инициализация копирования будет некорректной. Результат вызова функции преобразования, как описано для инициализации копирования без ссылки, затем используется для прямой инициализации ссылки. Для этой прямой инициализации определяемые пользователем преобразования не рассматриваются.

Не очень ясно, является ли значение std::string prv-квалифицированным, но в любом случае значение prvalue будет тогда используется для инициализации ссылки, которая определяется p5.2.1, которая требует, чтобы prvalue наследовал cv-квалификаторы инициализируемой ссылки. Итак, ясно, что созданный временный объект будет иметь тип const std::string.

Итак, в:

const std::string& name = "somename";

вы получите const временный, но когда вы сделаете

std::string&& name = "somename";

Вы получаете временный не const. Cv-квалификация временного соответствия совпадает с квалификацией ссылки.

...