Безопасно ли перемещать элементы списка инициализаторов?

Возможный дубликат:
initializer_list и семантика перемещения

В этом коде:

#include <vector>
#include <initializer_list>

template<typename T>
class some_custom_container : public std::vector<T>
{
public:
   some_custom_container(const std::initializer_list<T>& contents)
   {
      for (auto& i : contents)
        this->emplace_back(std::move(i));
   }
};

class test_class
{};

int main()
{
    test_class a;

    some_custom_container<test_class> i = { a, test_class(), a };
}

Насколько я понимаю, все объекты в { a, test_class(), a } построены безопасно: именованные объекты копируются, а неименованные объекты перемещаются для создания списка initializer_list. После этого этот initializer_list передается по ссылке конструктору some_custom_container.

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

Безопасен ли этот конструктор? Я имею в виду, что в странной ситуации, например, если T оценивается как ссылка & или &&, всегда ли вектор хорошо заполнен (содержит безопасные объекты)?

Если это так, то почему реализации конструктора initializer_list контейнеров stl не реализованы таким образом? Насколько я знаю, их конструкторы копируют, а не перемещают содержимое.


person Peregring-lk    schedule 19.12.2012    source источник
comment
Он даже не компилируется, потому что списки инициализаторов предоставляют только постоянный доступ к своему содержимому, и вы не можете перейти от ссылок к константам. См. также: stackoverflow.com/questions/8468774/   -  person R. Martinho Fernandes    schedule 19.12.2012
comment
Это не помешает его компиляции, только перемещению. Будет вызван конструктор копирования.   -  person Puppy    schedule 19.12.2012


Ответы (1)


initializer_list предоставляет только const доступ к своим элементам. Вы можете использовать const_cast для компиляции этого кода, но тогда ходы могут закончиться неопределенным поведением (если элементы initializer_list действительно константы). Так что нет, это не безопасно делать это перемещение. Для этого есть обходной путь, если он вам действительно нужен.

person R. Martinho Fernandes    schedule 19.12.2012
comment
Рассмотрим идиому in‹T›, описанную в cpptruths (cpptruths.blogspot.com/2013/09/). Идея состоит в том, чтобы определить lvalue/rvalue во время выполнения, а затем вызвать перемещение или копирование-конструкцию. in‹T› обнаружит rvalue/lvalue, даже если стандартный интерфейс, предоставляемый initializer_list, является константной ссылкой. - person Sumant; 24.09.2013
comment
@Sumant Действительно ли этот огромный беспорядок обеспечивает какие-либо измеримые преимущества для производительности или использования памяти, и если да, то достаточно большое количество таких преимуществ, чтобы адекватно компенсировать то, насколько ужасно это выглядит, и тот факт, что требуется около часа, чтобы понять, что он пытается сделать? Я как-то сомневаюсь. - person underscore_d; 09.08.2016