LINUX.ORG.RU

Что мешало реализовать семантику переноса еще в Си++ 03

 , ,


1

3

Собственно, сабж.

Кто в курсе подскажите, какие были причины такой долгой привязанности к избыточному копированию в куче?

Что мешало запилить эту фишку еще в 2003?

★★★★★

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

Да хоть в чистом Си.

В C++11 сделали исключительно одно: синтаксический сахар, заставляющий компилятор автоматически вызывать методы с семантикой переноса, где это уместно.

Я прекрасно помню, как в каком-то учебном проекте запилил свой аналог move semantics (через статический метод move()) — примерно года за два до C++11. Правда, в SFINAE я тогда не умел, поэтому получилось криво и вербозно.

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

Что мешало запилить эту фишку еще в 2003?

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

DarkEld3r ★★★★★
()

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

Legioner ★★★★★
()
Ответ на: комментарий от DarkEld3r
#include <iostream>
#include <memory>
using namespace std;
 
int main(int argc, char **argv)
{
    int *i = new int;
    auto_ptr<int> x(i);
    auto_ptr<int> y;
 
    y = x;
 
    cout << x.get() << endl; // Print NULL
    cout << y.get() << endl; // Print non-NULL address i
 
    return 0;

Вроде этого примера из Вики, да?

P.S. Хотя цитата из той же Википедии:

Because of its copy semantics, auto_ptr may not be used in STL containers that may perform element copies in their operations.

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от Legioner

Вот это больше похоже на правду.

Тогда получается, что в C++11, его просто стандартизировали и «обернули в сахар».

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

auto_ptr, по сути, реализовывал именно перемещение.

Перемещение прав владения ресурсом. Поверх этого можно нагородить своих костылей, но к move-semantics из C++11\14 это будет иметь крайне опосредованное отношение.

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

А, ну таки, потому-что destructive copy же!

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

А если в паре предложений, без волокиты ;-)

Twissel ★★★★★
() автор топика

Так вся фишка во встроенности в язык фишки по определению того, временный объект или нет. Вручную перенести во многих случаях можно было(через тот же swap в контейнерах), а для возвращаемых значений был rvo.

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

Компиляторы только rvo умели. Все остальное нужно было только руками делать. И в техже контейнерах могло происходить копирование данных, которого сейчас уже не будет.

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

Вот теперь более менее ясно)

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

синтаксический сахар

Не надо всё подряд так называть. Это — не синтаксический сахар, ибо делается не на уровне синтаксиса.

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

делается не на уровне синтаксиса

Именно на уровне синтаксиса. Добавили новый «модификатор типа» && и определили его семантику аналогично ссылке, но так, чтобы механизм перегрузки предпочитал именно его в том случае, когда рассматривается rvalue.

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

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от Twissel

Да где ж я его сейчас найду. У меня и код-то наверняка не остался, потому что в те тёмные времена я не умел в SCM :]

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

Ты описываешь семантический анализ и семантическое преобразование, причем собственно синтаксис остается старым. Сомневаюсь, что это уместно так называть. Хотя фиг знает, строгого определения термина я не видел, да и не термин это...

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

правильнее это назвать полноценной поддержкой компилятором)

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

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

Поддержка этой семантики, не?

Понятно, что раньше компилятор позволял это руками делать, но «узаконенного комфорта» не было.

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

Сознание он ломал у неокрепших умов.

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

DarkEld3r ★★★★★
()
Последнее исправление: DarkEld3r (всего исправлений: 1)
Ответ на: комментарий от Twissel

Тогда получается, что в C++11, его просто стандартизировали и «обернули в сахар».

Я так понимаю, что речь про RVO/NRVO - это немного не то. Оно вполне себе работает параллельно с текущей «семантикой переноса».

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

но к move-semantics из C++11\14 это будет иметь крайне опосредованное отношение.

Принцип-то такой же. И реализация копирующего конструктора у auto_ptr и текущих move-конструкторов одинаковая. Понятое дело, что без нормальной поддержки оно намного менее удобное.

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

Возврат объекта из вызываемой функции в вызывающую - это первое копирование, его убирает (опционально) (N)RVO. Присваивание его переменной, например, это второе копирование, его убирает семантика переноса, если она реализована для класса.

Поэтому в зависимости от обстоятельств такой код производит от 0 до 2 копирований =)

x = foo();

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

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

Да ты дурак похоже. 8 лет делать синтаксический сахар?

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

Разумеется, речь о том, что было сделано в данном контексте. Я не говорю, что ссылки на rvalue — единственное, что было добавлено в язык в C++11 :]

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

Раньше не было возможности определить, что это «временный объект», создаваемый в массовом порядке Поэтому и копировали. Сейчас она есть.

anonymous
()

Хорошая статья для общего развития.

Где я недавно исправил маленькую опечатку в тексте, которую за три года не заметили :]

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от intelfx

А я писала о том, что ты написал глупость. Разницу между синтакс. сахаром и работой над компилятором в течении 8 лет для реализации семантики std::move тебе понятна?

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

и работой над компилятором в течении 8 лет для реализации семантики std::move

Wat?

Я только что прочёл хрень. Перефразируй.

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

Я прекрасно помню, как в каком-то учебном проекте запилил свой аналог move semantics (через статический метод move()) — примерно года за два до C++11.

Ваня, обязательно свяжитесь с нами alumni@skolkovo.ru. Вера Орлова. Менеджер по работе с проактивными студентами Бизнес-Школы «Сколоково».

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

Я только что прочёл хрень. Перефразируй.

Грех это - смеяться над глупыми.

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

Вера, и что вы вот сразу уже лезете со своим «СколкКОГО»? Вас уже закроют скоро, штобы вы знали. Ваня, хороший мальчик, им надо ихать в Израль, и кредит там взять на квартиру.

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

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

Его может убрать «copy elision» и без семантики переноса.

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

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

LOL, а я и придумал RAII для С, просто нужно руками везде добавлять код.

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

Boost.Move

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

forCe
()

Реализации есть(см. вышел ссылку на Boost.Move). Но вещи такого уровня нужно иметь в языке.

Так получилось, что C++, вслед за Си, использует семантику значений. В Си для передачи по ссылке использовались указатели. И там перенос/копирование всегда идет от решаемой задачи. И типы всегда «открыты». В C++, с появлением определенных средств абстракции и возможности создавать свои типы, практически не отличимые от встроенных в язык, проблема с копированием встала острее. Семантика переноса стала неудобной из-за инкапсуляции. Использовать какое-то соглашение для методов, осуществляющих перенос, так же было неудобно, из-за особенностей сообщества и использования языка - единых стандартов нет и быть не может. Кроме того, из-за перегрузки операторов пришлось добавлять в систему типов странную штуку - ссылки(странные они потому, что являются типами, при этом имея столько оговорок, что в них запутаться очень просто, мне кажется, что их не стоило делать типами), но это немного отдельная история.

Теперь же, у нас появилась стандартная возможность, не зависимая от стандартов именования, известная компилятору(т.е. он может ее использовать самостоятельно, без указания программистов - у временных объектов можно забирать данные без проблем), управляемая программистом(мы сами определяем для своего типа операции переноса, если нас не устраивают стандартные).

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

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

Хм. Смотри, ты можешь написать пару кросскомпиляторных макросов для RAII в Си(через __attribute__((cleanup(clear_fun)) для gcc/clang и __try с __finally для m$). Но это не будет стандартным способом. Но это будет RAII.

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

Лучший ответ, имхо.

Благодарю.

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

Семантика переноса стала неудобной из-за инкапсуляции.

Можно более подробно объяснить это предложение.

Хочу, чтобы в этой теме не осталось белых пятен)

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

Думаю, тут имелось в виду, что в си ты сам решаешь, как и что переносить/копировать. Там нет перегрузки операторов, там тип или открыт полностью, или закрыт совсем (т.е. ты можешь работать только с указателем). А в крестах, когда у тебя тип закрыт, у него есть только стандартные средства: конструктор копирования, оператор присваивания и пр. И пока не появились стандартные средства для переноса, у тебя по сути не было общего способа для перемещения, а в потроха объекта ты залезть не мог(без нарушения инкапсуляции). В результате те же контейнеры в стандартной библиотеке ничего, кроме копирования, не могли делать, т.к. работают с разными типами и стандартные операции это все, что у них есть. Теперь в их распоряжении есть и операции для переноса.

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