2014-01-15 2 views
2

Пусть множество объектов будет положить в станд :: вектор контейнера, и они могут быть сделаны в следующих двух способов:C++ контейнер с объектом или с указателем объекта

Решение 1

std::vector<MyObject> objArray; 
    for(int i=0; i<100; i++) 
    { 

     MyObject obj(i); 
     objArray.push_back(obj); 
    } 

раствор 2

std::vector<boost::shared_ptr<MyObject> > objArray; 
    for(int i=0; i<100; i++) 
    { 

     MyObject *p_obj = new MyObject(i); 
     objArray.push_back(p_obj); 
    } 

Так что мой вопрос здесь: есть ли некоторые критерии, которые мы можем следовать при выборе одного решения от них? Благодарю.

+3

Не выделяйте динамически, если вы можете избежать этого. – Borgleader

+0

Я готов поспорить, что даже если вы * do * должны динамически выделять, вы не должны использовать 'shared_ptr', а' unique_ptr'. –

+0

@JohnDibling, по крайней мере, он использует интеллектуальные указатели вместо сырых. – Borgleader

ответ

2

В целом, я бы выбрал решение # 1, то есть vector<MyObject>.

Это проще, чем # 2 (vector<shared_ptr<MyObject>>).

С # 1, вы можете иметь хороший модуля памяти локальность, поскольку MyObject экземпляры хранятся последовательно в памяти, что очень кэш-дружественных (и так эффективно).
Вместо этого, с # 2, значения указателей сохраняются последовательно в векторе, но объекты, на которые указывает, рассеиваются в куче, поэтому у вас нет хорошей локальности в этом случае.

Однако могут быть исключения из общего правила. Например, я бы использовал опцию vector<shared_ptr<MyObject>>, если экземпляры MyObject тяжелы для копирования и не дешевы для перемещения. В этом случае семантика указателя может помочь.

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

Заметим также, что, если вы используете C++ 11/14, вы все равно можете иметь указатель семантику, но более эффективным способом, чем shared_ptr: на самом деле, вы можете использовать std::unique_ptr. unique_ptr не имеет блока управления (типичный для shared_ptr), не имеет взаимосвязанных операций приращения и уменьшения для счетчика ref и, как правило, быстрее и компактнее, чем shared_ptr. Если вам не нужна семантика совместного использования, и вы можете использовать компилятор C++ 11, unique_ptr - очень хорошая альтернатива shared_ptr.

Заметим также, что вы можете сделать vector<shared_ptr<...>> немного более эффективным, если вы используете правильный аллокатора для объекта: вместо того, чтобы использовать сырой new, рассмотреть возможность использования make_shared. Он имеет некоторые преимущества, такие как создание блока управления и объекта в последовательных ячейках памяти, поэтому у вас лучше локализация памяти, чем блок управления, созданный на куче, удаленном от управляемого объекта.

+0

Дополнительные прецеденты: Наследование, объекты, общие для проекта, копии на самом деле не так важно, как 'std :: vector' может быть перемещен – Paranaix

+1

@Paranaix: Копии важны в C++ 98/03 (я не уверен, может ли OP использовать компилятор C++ 11 +). Более того, если 'MyObject' является большим POD или содержит некоторые важные элементы данных POD, перемещения могут быть важными и дорогими, и что-то вроде семантики указателя может пригодиться. Во всяком случае, ключевой момент: _ «Когда сомневаетесь, измерьте». _. Но я думаю, что можно с уверенностью предположить, что общее правило заключается в том, чтобы избежать распределения кучи, если это возможно, поэтому предпочитайте 'vector '. Конечно, есть исключения из этого общего правила. –

+0

Конечно, но я имел в виду, что сам вектор можно перемещать, а не его членов. Только указатели на выделенную память кучи меняются местами, поэтому вся эта операция вообще не касается реальных объектов. – Paranaix

3

Есть ли какие-то критерии, которыми мы можем следовать при выборе одного из них?

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

+1

Наследование такого случая – Paranaix

+0

@Paranaix: IIRC, была [очень интересная сессия] (http://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil) на Channel9 от Going Native 2013, в котором Шон Родитель описал способ предложить своего рода политическое поведение без использования наследования. (Возможно, что-то было и в этом отношении [здесь] (http://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning).) –

1

Выбор прост:

  • Если объект хранится не полиморфный - сохранить объект.
  • Если объект является полиморфным и обрабатывает полиморфизм внутри (обертка), он сохраняет объект.
  • В противном случае хранения unique_ptr или shared_ptr умна

избежать последнего случая (если это не деталь реализации).

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