2014-01-13 6 views
8

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

Уже существует множество не скопируемых объектов в C++ 11, например std :: unique_ptr. Эти объекты полагаются на семантику переноса полностью, потому что перемещение с объекта позволяет его недействительным. Это важно (imho) для популярных шаблонов дизайна, таких как RAII.

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

Это, очевидно, важно во время жизни объекта из-за его постоянной. В конце его жизни, когда деструктор вызывается, объект (несуществующий) ненадолго ненастроен.

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

Рассмотрим простую ситуацию, когда unique_ptr используется в unordered_set. Вы можете использовать insert с помощью конструктора перемещения (или построить «emplace»), однако, если вы хотите переместить этот указатель на другой неупорядоченный_set (т. Е. Сохраняя его const), это было бы невозможно.

Существенный, есть iterator insert((possibly const) key&&), но нет const key&& erase(iterator). На самом деле это было бы невозможно. Контейнер может быть расширен только для возврата указателя на ключ и забыть об этом.

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

EDIT: Я должен указать, что const MyClass&& ~MyClass() const на самом деле имеет больше смысла. Деструктор не должен изменять anyhting, только уничтожает объект, как если бы он больше не был действительным дескриптором для любого контролируемого им ресурса.

+0

объекты Const также не 'const' во время строительства. – woolstar

+0

Более подходящий форум для этого был бы одним из первых 2 на этой странице: http://isocpp.org/forums –

+0

По существу он копировал бы только то, что ему нужно (это то, что означает движение в C++ 11), в новый объект, а затем уничтожает старый, как обычный ход, но происходит, но для не-temp – user3125280

ответ

10

Имхо вы определили настоящую необходимость.

Ваше решение звучит так же, как то, что я назвал деструктивная семантика перемещения. Эта возможность описана в original move semantics proposal. Я думаю, что такой дизайн возможен, хотя он не без проблем. Насколько я знаю, никто не работает в этой области в комитете по стандартизации.

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

N3645 - это предложение только для библиотеки, которое помещает вложенный контейнер node_ptr в каждый контейнер. node_ptr очень похож на unique_ptr. Он имеет уникальное право собственности на узел в ассоциативном контейнере. Но когда вы разыгрываете его, вы получаете неконстантный доступ к value_type в узле, а не только к самому узлу. extract и insert членов добавляются в ассоциативные контейнеры, позволяющие вставлять и удалять узлы (принадлежащие node_ptr) в/из контейнеров.

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

set<move_only_type> s; 
s.emplace(...); 
move_only_type mot = move(*s.extract(s.begin())); // extract, move, deallocate node 

Обратите внимание, что s.extract является noexcept, как это ~node_ptr() конечно. Если конструкция перемещения move_only_type равна noexcept, то вся эта операция составляет noexcept. В противном случае, если бросок строится, set остается, как если бы элемент был удален из set.

В настоящий момент никакого прогресса в отношении N3645. Он не был проголосован за рабочий проект, и я не уверен, что он когда-либо будет.

Обновление C++ 17

Я стою исправлено: Функциональность я описал выше, был избран в C++ 17 с P0083R3. Спасибо Cosme за то, что напомнил мне об этом в комментариях ниже.

+0

спасибо, это тот ответ, который я искал. Я понимаю, что библиотека может быть изменена, чтобы решить этот конкретный пример, но я надеюсь, что люди, читающие это, понимают, что это всего лишь конкретный пример. Да, «деструктивная семантика движения» - это именно та проблема, которую я пытался обсудить. – user3125280

+0

. Последняя редакция упомянутого предложения выше: [P0083R3] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0083r3.pdf) – Cosme

+0

Спасибо! Обновленный ответ с этой информацией. –

2

Извините, но помещение испорчено.

unordered_set фактически не содержит const объектов. Это просто не дает вам доступ на запись к содержащимся элементам. Это свойство только для аксессуаров.

Можно было бы добавить функцию key erase(iterator), которая просто перемещает элемент во временный. Я не уверен, зачем вам нужен key&&.

Что касается const MyClass&& ~MyClass() const, это не имеет смысла по трем причинам: dtors не имеет ни типов возврата, ни классификации CV, ни разрешения перегрузки для них.

+0

, конечно, он не имеет смысла, поскольку он стоит, это не вопрос. «Можно было бы добавить функцию стирания ключа (итератора), которая просто перемещает элемент во временный». Нет. Вы не можете перемещаться из константы, за исключением оператора const move. Такой оператор эквивалентен оператору const const. Проблема в том, что он может быть вызван в любом месте кода. Как правило, класс, не подлежащий копированию, используется для обозначения уникального объекта - как «перемещение временной» работы? что происходит, когда оригинал, перемещенный из объекта, уничтожается? Он не может быть изменен, поэтому он освобождает любой ресурс, который он удерживает. – user3125280

+0

В принципе, единственное решение - разрешить доступ к дескриптору памяти (с его собственными плюсами и минусами и очень не общий, и не может решить проблему того, где объект удален (см. [Здесь] (http: //meetingcpp.com/index.php/br/items/c1y-move-copy-destructors.html) для других мысли по подобной теме.)) или предоставить некоторый примитив, который позволяет строить из объекта в конце (это единственный способ предотвратить двойное удаление, как это было вызвано перемещением), и мое предложение - один из таких возможных примитивов (только пример, я подозреваю, что есть лучшие способы) – user3125280

+0

, а также неупорядоченный_set - это просто пример, (он может иметь объекты const), и переход от объекта приведет к аннулированию хэша (так эффективно он должен иметь константные ключи с внешней точки зрения) – user3125280

1

Итак, в основном вы говорите, что нужно переместить объект const в другой объект const и уничтожить оригинал?

Извините, но я думаю, что цель составляет const.

В противном случае было бы сформировать лазейку: вы могли бы уничтожить, переместить const объект из его ячейки памяти, то вы уничтожите передвигающийся другойconst объект в ячейку памяти первого (путем размещения new).

Теперь объект изменился, даже если это было const ... так, по существу const было бесполезно.

Смотрите комментарии ниже ...

+0

Да, (вызов другого, чем нормальный деструктор, так что нормальный вызов не вызывается дважды). На самом деле это не лазейка, в том смысле, что вы уже можете это сделать в C++. это неопределенное поведение и нарушает некоторые правила. Мне нужно было бы оглядеться больше, чтобы дать окончательный ответ, но я думаю, что удаление объекта означает, что он более недействителен для доступа к объекту по этому адресу (вам придется использовать хаки, чтобы сохранить эту память в любом случае при уничтожении объекта там). Даже если этот объект был const квалифицирован. Это просто неопределенно. Позвольте мне сделать идеологический пример. – user3125280

+0

[Я пытался] (http://ideone.com/e.js/u3iWSQ), но он, похоже, не обманул компилятор (поскольку он является незаконным). Я уверен, что вы знаете, что люди, не знакомые с C++, часто совершают ошибку, возвращая ссылку на временную. Это та же ситуация. Как только объект выходит из области видимости или удаляется указателем (или гипотетическим деструктором), он не имеет доступа к нему в любом случае. Const не делает объект постоянным, только чтение только во время его жизни. – user3125280

+0

@ user3125280: Хм, я уверен, что есть законные способы сделать это, но интересно, что я думаю, что проблема существует даже сейчас и не может иметь никакого отношения к вашему предложению. Например, 'struct S {char x; }; 'char buf [sizeof (S)];' S const * p = new (buf) const S(); 'foo (p);' S перемещен (p-> ~ S()); '' new (buf) const S (перемещен. ~ S()); 'Упс, мы просто изменили цель' p', даже если он был сконструирован как объект 'const' ... возможно, ваше предложение не влияет это ведь? – Mehrdad

 Смежные вопросы

  • Нет связанных вопросов^_^