Вектор С++, эффективно добавляющий элементы

Предположим, у меня есть следующий код:

#include <iostream>
#include <vector>
using namespace std;

class X {
public:
  int x[1000];
  X(int y) { for (int i = 0; i < 1000; i++) x[i] = y; }
};

int main() {
  vector<X> v;
  X x0(0);
  X x1(1);
  X x2(2);
  v.push_back(x0);
  v.push_back(x1);
  v.push_back(x2);
  cout << v[2].x[33] << endl;
  return 0;
}

Если я правильно понимаю, в моем коде я выделяю память в стеке для x0, x1 и x2, а затем копирую это содержимое в память, выделенную для меня vector. Кроме того, насколько я понимаю, семантика перемещения здесь не поможет, потому что это не совсем так, как X содержит указатель на ресурс, расположенный где-то еще.

Могу ли я напрямую вызвать конструктор блока необработанной памяти, выделенного для меня vector? Если нет, то как правильно поступить в подобных ситуациях?


person math4tots    schedule 21.05.2013    source источник
comment
мой непрошенный совет: не делайте классы такими большими.   -  person Benjamin Lindley    schedule 22.05.2013
comment
4 КБ данных в структуре для вас слишком много? Пара обычных массивов char доставит вас туда, даже не осознавая этого.   -  person StilesCrisis    schedule 22.05.2013
comment
Семантика перемещения в основном полезна для классов подобных дескрипторам. Что приводит к вопросу: Почему вы боретесь с языком? Если x[1000] является заполнителем для структур, которые вы не можете показать здесь, мой следующий вопрос: являются ли эти структуры похожими на дескрипторы? Если вы действительно используете такие большие массивы, используйте vector‹int›. Не боритесь с языком.   -  person indeterminately sequenced    schedule 22.05.2013
comment
@StilesCrisis: Да, в общем, для меня это слишком. Именно по той очевидной причине, что это делает перемещение объектов класса слишком дорогим. Зачем мне иметь пару массивов символов размером 2000 в структуре, кроме как для очень конкретных целей, и вообще не для тех типов объектов, которых у меня достаточно, и я хотел бы поместить их в вектор?   -  person Benjamin Lindley    schedule 22.05.2013


Ответы (2)


Вам нужно использовать emplace_back С++ 11.

http://en.cppreference.com/w/cpp/container/vector/emplace_back

Кроме того, если вас беспокоят лишние копии/перемещения, попробуйте начать с v.reserve(3).

person StilesCrisis    schedule 21.05.2013
comment
Это также на удивление легко сделать в C++03 с итераторами IIRC - person Mooing Duck; 22.05.2013
comment
Вектор без копирования push_back в С++ 03 с итераторами? Скажи. - person StilesCrisis; 22.05.2013
comment
@StilesCrisis: передайте временный файл и позвольте оптимизирующему компилятору делать то, что он делает. - person John Dibling; 22.05.2013
comment
Как это связано с итераторами? - person StilesCrisis; 22.05.2013
comment
@StilesCrisis: я не говорил с push_back, я просто сказал создание элементов на месте с помощью итераторов. v.assign(begin, end); или аналогичный. - person Mooing Duck; 22.05.2013
comment
Вы можете создать их на месте, если вы можете жить с конструкцией по умолчанию. Я думаю, что этот пример конкретно о построении с передачей аргументов. - person StilesCrisis; 22.05.2013

Вы также можете использовать std::ref или boost::ref, если они доступны, и сохранить ссылку на объект в векторе, избегая таким образом копирования.

#include <iostream>
#include <vector>
#include <functional>
using namespace std;

class X {
public:
  int x[1000];
  X(int y) { for (int i = 0; i < 1000; i++) x[i] = y; }
};

int main() {
  std::vector<std::reference_wrapper<X> > v;
  X x0(0);
  X x1(1);
  X x2(2);


  v.push_back(std::ref(x0));
  v.push_back(std::ref(x1));
  v.push_back(std::ref(x2));
  cout << v[2].get().x[33] << endl;
  return 0;
}
person andre    schedule 21.05.2013
comment
Классный трюк, но он не сработает, если x0 и его друзья когда-нибудь выйдут за пределы области видимости, пока вектор все еще жив... это затрудняет использование для вещей общего назначения. - person StilesCrisis; 22.05.2013