Переместить семантику & amp; порядок оценки аргумента

Учитывая следующее:

std::string make_what_string( const std::string &id );

struct basic_foo
{
basic_foo( std::string message, std::string id );
};

struct foo
: public basic_foo
{
foo::foo( std::string id)
: basic_foo( make_what_string( id ), std::move( id ) ) // Is this valid?
{
}
};

Поскольку порядок оценки параметров в C ++ не определен, мне интересно,
линия

basic_foo( make_what_string( id ), std::move( id ) )

в приведенном выше коде действителен.

я знаю это std::move это не что иное, как приведение, но когда есть std :: string
ход ctor выполняется? После того, как все аргументы были оценены и пришло время позвонить
базовый конструктор? Или это делается при оценке параметров? В
другие слова:

Компилятор делает это:

std::string &&tmp2 = std::move(id);
std::string tmp1 = make_what_string(id);
basic_foo(tmp1, tmp2);

который действителен. Или это:

std::string tmp2 = std::move(id);
std::string tmp1 = make_what_string(id);
basic_foo(tmp1, tmp2);

который недействителен. Обратите внимание, что в обоих случаях порядок является «неожиданным».

23

Решение

Смотрите раздел 1.9:

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

а также

При вызове функции (независимо от того, является ли функция встроенной), каждое вычисление значения и побочный эффект, связанный с любым выражением аргумента или с выражением постфикса, обозначающим вызываемую функцию, упорядочивается перед выполнением каждого выражения или оператора в теле вызываемая функция. [ Заметка: Вычисления значений и побочные эффекты, связанные с различными выражениями аргументов, не являются последовательными. —конечная нота ]

Я думаю, что проблема заключается в том, что не очень ясно, считается ли инициализация параметров побочным эффектом, связанным с выражениями аргументов. Тем не менее, кажется, что это подкреплено разделом 5.2.2:

Инициализация и уничтожение каждого параметра происходит в контексте
вызывающая функция.

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

Когда вызывается функция, каждый параметр (8.3.5) должен быть инициализирован (8.5, 12.8, 12.1) с соответствующим аргументом. [ Заметка: Такие инициализации неопределенно упорядочены друг относительно друга (1.9) — конечная нота ]

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

std::string message = make_what_string(id);
std::string id = std::move( id );

std::string id = std::move( id );
std::string message = make_what_string(id);

Во втором случае make_what_string заканчивает работу с перемещенной строкой.

Итак, хотя std::move на самом деле ничего не двигается, важно то, что фактическое перемещение также не секвенировано относительно другого аргумента.

Определение конструктора перемещения basic_string(basic_string&& str) состояния:

[…] str остается в допустимом состоянии с неопределенным значением.

Таким образом, у вас нет неопределенного поведения, у вас есть неопределенное поведение.

16

Другие решения

Это не совсем верно. Порядок оценки аргументов функции не указан. Другими словами, вы не знаете, будет ли компилятор выбирать эту последовательность:

tmp1 = make_what_string(id);
tmp2 = std::move(id);
basic_foo(tmp1, tmp2);

или этот:

tmp1 = std::move(id);
tmp2 = make_what_string(id);  //id has already been moved from!
basic_foo(tmp2, tmp1);
7

По вопросам рекламы [email protected]