std:: vector, конструкция по умолчанию, C++11 и критические изменения


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

рассмотрим следующий сад-разнообразие общего тела идиомы класса:

struct S
{
    S() : p_impl(new impl) {}
private:
    struct impl;
    boost::shared_ptr<impl> p_impl;
};

веселье появляется, когда вы пытаетесь поместить их в векторы следующим образом:

std::vector<S> v(42);

теперь, с MSVC 8 по крайней мере, все элементы в v одинаковые impl член. На самом деле, что вызывает это vector конструктора:

template <typename T, typename A = ...>
class vector
{
    vector(size_t n, const T& x = T(), const A& a = A());
    ...
};

под сцены, только один

2   51   2011-04-22 23:28:30

2 ответа:

делает ли стандартный мандат C++03, что std::vector должен иметь конструктор, как указано выше, т. е. с аргументом по умолчанию? В частности, есть ли гарантия того, что записи векторного объекта будут скопированы вместо построенных по умолчанию?

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


что говорит стандарт C++11 об этом же пункте?

В C++11 этот конструктор был превращен в два конструктора.

vector(size_type n, const T& x, const Allocator& = Allocator()); // (1)
explicit vector(size_type n);                                    // (2)

за исключением того, что он больше не имеет аргумента по умолчанию для второго параметра, (1) работает так же, как и в C++03: x скопировать n раза.

вместо аргумента по умолчанию для x,(2) была добавлена. Этот конструктор значение-инициализирует n элементов в контейнере. Копии не делаются.

Если вам требуется старое поведение, вы можете убедиться, что (1) вызывается путем предоставления второго аргумента для вызова конструктора:

std::vector<S> v(42, S());

я рассматриваю это как возможность для прорывного изменения между C++03 и C++11. Я рассматриваю это как возможность для прорывного изменения между C++03 и C++11. Был ли этот вопрос исследован? Решено?

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

Я думаю, что решение для описанного вами случая использования не является оптимальным и не полным, поэтому у вас возникли проблемы с обновлением до C++11.

C++ всегда заботится о семантике, и когда вы пишете программу на c++, вам лучше понять свою семантику. Поэтому в вашем случае вы хотите создать N объектов, но пока вы их не меняете, вы хотите, чтобы они делили одну и ту же память для оптимизации. Хорошая идея, но как это сделать: 1) конструктор копирования. 2) статическая реализация + копирование конструктор. Вы рассматривали оба решения?

считайте, что вам нужно M векторов N объектов, сколько раз общая память будет выделена, если вы выберете 1-й сценарий? Это M, но зачем нам нужно выделять память M раз, если мы хотим создать векторы, содержащие объекты MxN?

поэтому правильная реализация здесь должна указывать на статическую память по умолчанию и выделять память только в случае изменения объекта. В таком случае выделение M векторов N объектов даст вам... Один выделение "общей" памяти.

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