LINUX.ORG.RU

C++ std::move

 ,


0

3

Такой глупый вопрос. Есть небольшой код:

std::string s1 = "s1";
std::string s2 = "s2";
s2 = std::move(s1);

Почему move работает как swap? То есть в конце значения такие: s2=«s1», s1=«s2». Я ожидал, что будут: s2=«s1», s1="". Использую gcc 4.9.


Ответ на: комментарий от anonymous

Считай что это и есть невалидное состояние с вероятностью сегфолта, а гарантировать его нереально.

Смотря что понимать под «гарантией». Если «гарантия на любой прибабахнутой платформе», мне она и не нужна.

Но пойнт в... см. выше.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Вот за такие трюки Си++ и должен бы умереть.

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

Iron_Bug ★★★★★
()
Ответ на: комментарий от tailgunner

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

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

и в этом плане плюсы достаточно эффективно их отпугивают.

Лол :-) На этом языке пишут все, кому не лень :-) Потому что считается, что компиляторы цепепе генерируют быстрый код :-)

неосиляторы недовольны отсутствием защиты от дурака и не лезут писать код. это зер гут.

Это поэтому на цепепе написано столько «прекрасного»? :-)

anonymous
()
Ответ на: комментарий от Iron_Bug

гарантия отсутствия школоты

все ваши подгузники оставьте себе. серьёзный программист знает, что он делает.

«From the people who brought you Heartbleed».

tailgunner ★★★★★
()
Ответ на: комментарий от Iron_Bug

серьёзный программист знает, что он делает.

Скорее он делает то, что знает :-)

для тех, кто не знает, что он делает, есть песочницы типа жабы и до-диеза, вплоть до вижуал васика.

А для тех, кто знает, что он делает, есть стандарт почти на полторы тысячи страниц :-)

anonymous
()
Ответ на: комментарий от Iron_Bug

что язык предоставляет возможность писать код, который работает быстро.

И быстро превращаться в нечитаемую лапшу :-)

anonymous
()
Ответ на: комментарий от anonymous

И быстро превращаться в нечитаемую лапшу :-)

-- прокукарекал лишпер.

Уже забыл, как тебя говном накормили, когда ты лишповые байндинги к Qt притащил?

anonymous
()
Ответ на: комментарий от anonymous

 — прокукарекал лишпер.

Хахаха :-)

Уже забыл, как тебя говном накормили, когда ты лишповые байндинги к Qt притащил?

Держи нас в курсе :-)

anonymous
()
Ответ на: комментарий от tailgunner

Но почему именно сегфолт?

В любом случае, любителям zerocost-всего-на-свете едва ли понравится такая идея, ведь объект в любом случае должен корректно уничтожаться. Получается, что такое поведение придётся реализовать флажком is_moved_out и его проверкой во всех методах, что может таки заметно замедлить код.

Softwayer ★★
()
Ответ на: комментарий от Softwayer

Но почему именно сегфолт?

Чтобы не пропустить.

объект в любом случае должен корректно уничтожаться

Что ему помешает это сделать?

Получается, что такое поведение придётся реализовать флажком is_moved_out

Не получается.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Чтобы не пропустить.

Очень странная аргументация. Обосновывать я это, естественно, не стану.

Не получается.

Хорошо, как ещё сделать так, чтобы length() падал? Если что, под «флажком» не подразумевалась именно булева переменная или что-то в таком духе, но объект должен уметь понимать, moved-out он или нет, и ему придётся так или иначе это проверять.

Softwayer ★★
()
Ответ на: комментарий от Softwayer

Очень странная аргументация. Обосновывать я это, естественно, не стану.

Я и не просил обоснований.

Хорошо, как ещё сделать так, чтобы length() падал?

И почему же он не должен падать? UB, все дела. Послать убийц к твоей матери - вполне валидное поведение.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Я не утверждаю, что он не должен падать — я спрашиваю, как это реализовать без явной проверки на то, moved-out ли объект.

Softwayer ★★
()
Ответ на: комментарий от Softwayer

Я не утверждаю, что он не должен падать — я спрашиваю, как это реализовать без явной проверки на то, moved-out ли объект.

Реализуй с проверкой.

tailgunner ★★★★★
()

Почему move работает как swap?

After move, the moved object is in valid but an unknown state.

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

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 2)
Ответ на: комментарий от tailgunner

Флажок или какое-нибудь (length_ != 0 && buf_ == nullptr) — какая разница, главное, что в дешёвых операциях появляются проверки, способные замедлить их в разы.

Softwayer ★★
()
Ответ на: комментарий от peregrine

Нет. Просто разработчик на C++ должен уметь сказать что делает каждая функция в его коде. Если он этого не умеет, то он не разработчик на C++.

Нет, он не разработчик на С++, а разработчик своего кода на С++.

А с поправленной аргументацией: уметь сказать, что делает каждая валидная строчка на С++ в любом С++ коде. Думаю, разработчиков на С++ вообще нет. Если несколько часов / дней поиска инфы и обсуждения на форумах не учитывать. А если учитывать, то, может, и есть пара очень вялых разработчиков на С++.

gag ★★★★★
()
Ответ на: комментарий от anonymous

В комитете сидят опытные люди с реальными проблемами, а не демоны.

Учитывая качество их работы, трудно в этом не усомниться.

gag ★★★★★
()
Ответ на: комментарий от xaizek

Потому что это эффективная реализация, а значения у «moved from» объекта неспецифицированно, т.е. std::swap вполне себе валидная реализация

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

former_anonymous ★★★
()
Ответ на: комментарий от former_anonymous

swap чего с чем?

swap объекта слева от знака равно с объектом справа. В первом посте речь идёт о move assignment, а не move construction.

xaizek ★★★★★
()
Ответ на: комментарий от Iron_Bug

нет, умереть должны неосиляторы, которые не читают стандартов и потом говнокодят

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

Freyr69 ★★★
()
Ответ на: комментарий от Softwayer

Флажок или какое-нибудь (length_ != 0 && buf_ == nullptr) — какая разница, главное, что в дешёвых операциях появляются проверки, способные замедлить их в разы.

Дорогой теоретик :-) Почему ты так считаешь? :-) Давай сравним at() и operator[] у std::vector<> :-)

at()

#include <vector>

int main(int argc, char *argv[])
{
  constexpr std::vector<int>::size_type sz = 100000000;
  std::vector<int> v;
  v.resize(sz, 1);
  for (std::vector<int>::size_type i = 0; i < sz; ++i)
    v.at(i) = 0;
  return 0;
}

operator[]

#include <vector>

int main(int argc, char *argv[])
{
  constexpr std::vector<int>::size_type sz = 100000000;
  std::vector<int> v;
  v.resize(sz, 1);
  for (std::vector<int>::size_type i = 0; i < sz; ++i)
    v[i] = 0;
  return 0;
}

$ g++ -O3 -std=c++14 at.cpp -oat
$ g++ -O3 -std=c++14 operator.cpp -ooperator
$ time ./at

real	0m0.282s
user	0m0.132s
sys	0m0.148s
$ time ./operator

real	0m0.253s
user	0m0.116s
sys	0m0.136s

Где тут «в разы»? :-)

anonymous
()
Ответ на: комментарий от Gorthauer

Можно и просто warning оставить на тему use after move

В каких компиляторах он есть?

tailgunner ★★★★★
()
Ответ на: комментарий от i-rinat

доказать, что всегда [...]

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

tailgunner ★★★★★
()
Ответ на: комментарий от Softwayer

Флажок или какое-нибудь (length_ != 0 && buf_ == nullptr) — какая разница

Разница в том, есть флажок или нет.

проверки, способные замедлить их в разы.

Давай на порядки - чего их жалеть.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

Дорогой теоретик :-) Почему ты так считаешь? :-) Давай сравним at() и operator[] у std::vector<> :-)

Поздравляю тебя, Шарик, ты успешно сравнил v.resize(sz, 1) с v.resize(sz, 1), немного разбавив его [] и at.

anonymous
()
Ответ на: комментарий от anonymous

Поздравляю тебя, Шарик, ты успешно сравнил v.resize(sz, 1) с v.resize(sz, 1), немного разбавив его [] и at.

Ну разбавь его много с помощью [] и at :-) Результат запости сюда, ламерок :-)

anonymous
()
Ответ на: комментарий от anonymous

Ну разбавь его много с помощью [] и at :-) Результат запости сюда, ламерок :-)

Зачем, это ты сидишь в своей луже, вот и продолжай это делать.

anonymous
()
Ответ на: комментарий от anonymous

Зачем, это ты сидишь в своей луже, вот и продолжай это делать.

Т.е. замеров не будет, кода не будет :-) Не забудь принять душ :-)

anonymous
()
Ответ на: комментарий от utf8nowhere

Как известно ещё отсюда, у тебя какие-то серьёзные проблемы с ЭВМ и/или ПО.

Как уже было сказано, проблемы в сообществе, а не с ЭВМ и/или ПО :-)

anonymous
()
Ответ на: комментарий от anonymous

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

Вариант с at:

#include <vector>

int main()
{
	std::vector< int > v;
	v.resize( 50, 0 );

	for( int i = 0; i != 100000000; ++i )
		for( std::size_t j = 0, j_max = v.size(); j != j_max; ++j )
			v.at( j ) = i;
}
real	0m7.559s
user	0m7.324s
sys	0m0.004s

Вариант с operator[]:

#include <vector>

int main()
{
	std::vector< int > v;
	v.resize( 50, 0 );

	for( int i = 0; i != 100000000; ++i )
		for( std::size_t j = 0, j_max = v.size(); j != j_max; ++j )
			v[ j ] = i;
}
real	0m3.175s
user	0m2.976s
sys	0m0.004s

eao197 ★★★★★
()

Использую gcc 4.9

Некрофил! Уже давно gcc 6.2.1 есть.

anonymous
()
Ответ на: комментарий от eao197

А давай внесём в твой код маленькие коррективы и посмотрим :-)

Модифицированный вариант с at:

// at modified :-)

#include <vector>

int main()
{
    std::vector< int > v;
    v.resize( 50, 0 );

    const auto v_size = v.size();
    for( int i = 0; i < 100000000; ++i )
        for( std::size_t j = 0; j < v_size; ++j )
            v.at( j ) = i;
}

Модифицированный вариант с operator[]:

// operator[] modified :-)

#include <vector>

int main()
{
    std::vector< int > v;
    v.resize( 50, 0 );

    const auto v_size = v.size();
    for( int i = 0; i < 100000000; ++i )
        for( std::size_t j = 0; j < v_size; ++j )
            v[ j ] = i;
}

Теперь смотрим:

vector_speed $ g++ -O3 -std=c++14 at_eao197.cpp -oat_eao197
vector_speed $ g++ -O3 -std=c++14 operator_eao197.cpp -ooperator_eao197
vector_speed $ g++ -O3 -std=c++14 at_modified.cpp -oat_modified
vector_speed $ g++ -O3 -std=c++14 operator_modified.cpp -ooperator_modified
vector_speed $ time ./at_eao197

real	0m3.580s
user	0m3.564s
sys	0m0.000s
vector_speed $ time ./operator_eao197

real	0m1.206s
user	0m1.196s
sys	0m0.004s
vector_speed $ time ./at_modified

real	0m1.597s
user	0m1.588s
sys	0m0.000s
vector_speed $ time ./operator_modified

real	0m1.098s
user	0m1.092s
sys	0m0.004s

Такие дела :-)

anonymous
()
Ответ на: комментарий от Iron_Bug

неосиляторы недовольны отсутствием защиты от дурака

Согласен. Я уже содрал и сдал в переработку всю изоляцию на проводах в квартире, достигая небывалой экономии.

vertexua ★★★★★
()
Ответ на: комментарий от Softwayer

любителям zerocost-всего-на-свете

Надо правильно говорить, разработчикам стандартов С++, так как филосовия zero-cost - это их обещание сообществу.

vertexua ★★★★★
()
Ответ на: комментарий от anonymous

Даже после демонстрации фокусов с разгоном микробенчмарка разница получается весьма ощутимой: 1.098 против 1.597.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Даже после демонстрации фокусов с разгоном микробенчмарка разница получается весьма ощутимой: 1.098 против 1.597.

Давай прикинем:

(let* ((at-time               1.597)
       (operator-time         1.098)
       (iterations-count      100000000)
       (diff-time             (- at-time operator-time))
       (1-operation-time      (/ diff-time iterations-count))
       (nanoseconds-ratio     (expt 10 9))
       (1-operation-time-nano (* 1-operation-time nanoseconds-ratio)))

  1-operation-time-nano)
4.989999999999998
Кем ощущается разница в 5 наносекунд на итерацию? :-) И почему надо стремиться выжимать из машины всё до последней капли, играясь в UB? :-) Что это за подход такой? :-)

anonymous
()
Ответ на: комментарий от anonymous

Никогда не сталкивались, скажем, с видеоконвертерами? Когда один пережимает видеофайл за два часа, а второй — за три?

Ну или численные расчеты, которые в одной реализации выполняются за 10 часов, а во второй — за 15?

eao197 ★★★★★
()
Ответ на: комментарий от tailgunner

Проблема не в перемещении или отсутствии контроля со стороны компилятора, а в том, что поощряется ублюдочный стиль попыток набрать миллиграмм скорости за счет UB.

А мне кажется, что проблема как раз в том, что границы слишком размыты и допустить UB случайно слишком просто. Если бы язык позволял явно очертить эти границы и предупреждал о их нарушении, то что плохого в «миллиграммах скорости»?

Да, вокруг языка полно людей, которые любят заводить разговоры о том, что все нюансы можно и нужно помнить и если допустил ошибку, то сам виноват и «недостоин» писать на С++, но я очень сомневаюсь, что в комитете их большинство. Или даже значимое количество.

DarkEld3r ★★★★★
()
Ответ на: комментарий от eao197

Никогда не сталкивались, скажем, с видеоконвертерами? Когда один пережимает видеофайл за два часа, а второй — за три?
Ну или численные расчеты, которые в одной реализации выполняются за 10 часов, а во второй — за 15?

Логика понятна :-) В таких особых случаях, когда совершенно ясно, что можно сэкономить несколько часов рантайма без особых усилий на поддержку, конечно можно оптимизировать локализованный узкий участок кода :-) Но когда всюду и везде пытаются играться в «скоростные игры», экономя 5 наносекунд на операцию, то тут уже вопрос об адекватности :-)

anonymous
()
Ответ на: комментарий от tailgunner

Я вот не знаю, но мне кажется вся std::move семантика делалась для парочки глубокобиблиотечных классов вроде std::unique_ptr, в которых уж надеюсь косяков не будет. И всякие отписки о UB нужны чтобы сохранять формальность. В реальном использовании коню (линтеру) интуитивно понятно что a_unique_ptr=std::move(b_unique_ptr), то b_unique_ptr просто не надо больше пользоваться.

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 1)

О, плюсосрач

Давайте уже честно признаем - треть проблем крестов в отсутствии явного понятия «неинициализированная переменная» на уровне языка при том, что неявно во многих случаях оно требуется по смыслу или уже неявно введено. В примере оп-поста самое разумное - считать s1 неинициализированной и не компилировать код, который её читает. Для кода типа int i;return i; уже выдаётся ворнинг. Но официально это оформить и энфорсить везде разработчикине хотят.

anonymous
()
Ответ на: О, плюсосрач от anonymous

официально это оформить и энфорсить везде разработчикине хотят

Потому что это невозможно строго определить везде. gcc ведь тоже пишет что-то типа «variable may be used uninitialized».

Поэтому более жизнеспособно предложение Майерса везде энфорсить инициализацию.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.