Как инициализировать вектор/список STL с классом, не вызывая конструктора копии

У меня есть программа C++, которая использует станд.:: список, содержащий экземпляры класса. Если я звоню, например. myList.push_back(MyClass(variable)); это проходит процесс создания временной переменной, и затем сразу копирует его в вектор и впоследствии удаляет временную переменную. Это совсем не столь эффективно, как я хочу, и сосет, когда Вам нужна глубокая копия.

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

Есть ли какой-либо путь вокруг этого (я не использую Visual Studio BTW)?

22
задан Michael Myers 5 April 2010 в 18:28
поделиться

6 ответов

Конструкторы перемещения C ++ 0x - это частичный обходной путь: вместо вызываемого конструктора копирования будет использоваться конструктор перемещения. Конструктор перемещения похож на конструктор копирования, за исключением того, что ему разрешено аннулировать исходный аргумент.

C ++ 0x добавляет еще одну функцию, которая будет делать именно то, что вы хотите: emplace_back . (N3092 §23.2.3) Вы передаете ему аргументы конструктору, затем он вызывает конструктор с этими аргументами (посредством ... и пересылки), поэтому никакой другой конструктор никогда не сможет быть вызванным.

Что касается C ++ 03, единственный вариант - добавить в класс неинициализированное состояние. Выполните фактическое построение в другой функции, вызываемой сразу после push_back . boost :: optional может помочь вам избежать инициализации членов класса, но это, в свою очередь, требует, чтобы они были копируемыми. Или, как говорит Фред, сделайте то же самое с изначально пустыми интеллектуальными указателями.

9
ответ дан 29 November 2019 в 05:18
поделиться

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

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

class Test
{
public:
  Test() { cout<<"Construct\n"; }
  Test(const Test& other) { cout<<"Copy\n"; }
  Test& operator=(const Test& other) { cout<<"Assign\n"; return (*this); }
};

Test rvo() { return Test(); }
int main()
{
  cout<<"Testing rvo:\n";
  Test t = rvo();
  cout<<"Testing list insert:\n";
  list<Test> l;
  l.push_back(Test());
}

И вот мой результат на MSVC ++ 2008:

Testing rvo:
Construct 
Testing list insert:
Construct
Copy

То же самое и для отладочной, и для выпускной сборок: RVO работает, временная передача объектов не оптимизирована.
Если я не ошибаюсь, ссылки Rvalue , добавляемые в стандарт C ++ 0x, предназначены для решения именно этой проблемы.

9
ответ дан 29 November 2019 в 05:18
поделиться

Используйте shared_ptr или shared_array для управления памятью, которую хочет выделить ваш класс. Затем предоставленный компилятором конструктор копирования просто увеличит счетчик ссылок, поскольку shared_ptr копирует себя. Важной концепцией использования стандартных контейнеров является то, что копирование ваших элементов будет дешевым. Стандартная библиотека делает копии повсюду.

1
ответ дан 29 November 2019 в 05:18
поделиться

Фактически, в этом случае компилятор может исключить копию.

Если ваш компилятор этого не делает, один из способов избежать копирования - это включить в список указатели вместо экземпляров. Вы можете использовать умные указатели, чтобы очистить объекты за вас.

4
ответ дан 29 November 2019 в 05:18
поделиться

Конструкторы перемещения C ++ 0x (доступные в VC ++ 2010 и последних компиляторах GNU) - это именно то, что вам нужно.

5
ответ дан 29 November 2019 в 05:18
поделиться

Проверьте библиотека ptr_container . В частности, я использую ptr_vector:

boost::ptr_vector<Foo> c;
c.push_back(new Foo(1,2,3) );
c[0].doSomething()

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

2
ответ дан 29 November 2019 в 05:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: