Контейнеры STL со ссылкой на объекты

c++ stl reference pass-by-reference

20321 просмотра

5 ответа

5654 Репутация автора

Я знаю, что контейнеры STL копируют объекты. Так скажи, у меня есть

list<SampleClass> l;

каждый раз, когда я делаю

SampleClass t(...);
l.push_back(t);

копия т будет сделана. Если SampleClass большой, то это будет очень дорого.

Но если я объявлю l контейнером ссылок,

list<SampleClass&> l;

Когда я делаю

l.push_back(t);

Будет ли это избегать копирования объектов?

Автор: Vendetta Источник Размещён: 10.10.2011 01:52

Ответы (5)


20 плюса

434 Репутация автора

Решение

К сожалению, нет, он не скомпилируется (по крайней мере, с stlport). Но альтернатива, которая заключается в хранении указателей на ваши объекты в контейнере, будет прекрасно компилироваться.

Это оставит вас с небольшим количеством дополнительного синтаксического шума вокруг вашего кода - вам нужно будет что-то новое, чтобы вставить их в ваш контейнер.

std::list<class_type*> l;
l.push_back(new class_type);

Однако, хотя объекты теперь не будут копироваться, они также не будут автоматически очищаться для вас при разрушении списка. Умные указатели решат это за вас, но за счет еще большего синтаксического шума. И поскольку вы не можете поместить std :: auto_ptr в стандартные контейнеры, потому что они не могут быть скопированы, вы должны использовать их двоюродных братьев с более тяжелым весом, общие указатели.

std::list<boost::shared_ptr<class_type> > l;
l.push_back(boost::shared_ptr<class_type>(new class_type));

Shared острие несет некоторые дополнительные издержки, но это минимально.

Автор: Dave Branton Размещён: 10.10.2011 02:07

4 плюса

9140 Репутация автора

Контейнеры стандартной библиотеки требуют, чтобы их типы были копируемыми; поскольку ссылки не являются, вы не можете хранить их в контейнерах для начала. Вы можете хранить указатели, если вы осторожны с временем жизни объекта. Boost имеет несколько контейнеров указателей, чтобы помочь с этим, или у вас есть умные указатели. Тем не менее, обратите внимание, что auto_ptrэто не копируется (поскольку стандарт определяет это для этой цели), поэтому shared_ptrи unique_ptrваши лучшие ставки сейчас. Оба являются стандартными в C ++ 11, а первый поддерживается через boost в C ++ 03.

Автор: Dennis Zickefoose Размещён: 10.10.2011 02:08

32 плюса

385470 Репутация автора

Если вы знаете, что делаете, вы можете создать вектор ссылок, используя std::reference_wrapper:

#include <functional>
#include <vector>

int main()
{
  std::vector<std::reference_wrapper<int>> iv;

  int a = 12;
  iv.push_back(a);  // or std::ref(a)

  // now iv = { 12 };

  a = 13;

  // now iv = { 13 };
}

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

Автор: Kerrek SB Размещён: 10.10.2011 02:16

1 плюс

5100 Репутация автора

Вы хотите контейнер указателей:

list<SampleClass*> l;
Автор: Mikhail Размещён: 10.10.2011 02:49

0 плюса

47 Репутация автора

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

Здесь у меня есть unique_ptr дерева, но я использовал стек STL для хранения необработанных указателей

void TreeTraversal(unique_ptr<BinaryTreeNode>& root) {
    stack<BinaryTreeNode *> _stack;

    BinaryTreeNode *p = root.get();
    _stack.push(p);

    while(!_stack.empty()) {
        p = _stack.top();
        _stack.pop();
        ...
        _stack.push(p->left);
        _stack.push(p->right);
    }
}

int main() {
    unique_ptr<BinaryTreeNode> root = unique_ptr<BinaryTreeNode>(new BinaryTreeNode(...));
    TreeTraversal(root);
}
Автор: saha Размещён: 13.01.2018 06:59
Вопросы из категории :
32x32