Сохраняет ли set :: insert копию или указатель C ++ - PullRequest
3 голосов
/ 26 февраля 2011

делает функцию set::insert сохраняет указатель на элемент или его копию. имеется в виду, могу ли я сделать следующий код, или я должен убедиться, что указатели не удалены?

int *a;
*a=new int(1);
set<int> _set;
_set.insert (*a);
delete a;
*a=new int(2);
_set.insert (*a);
delete a;

Я привел пример с int, но моя настоящая программа использует созданные мной классы.

Ответы [ 4 ]

12 голосов
/ 26 февраля 2011

Все контейнеры STL хранят копию вставленных данных. Посмотрите здесь в разделе «Описание» в третьем абзаце: Контейнер (и std::set моделирует Контейнер) владеет своими элементами. А для более подробной информации смотрите следующую сноску [1]. В частности, для std::set смотрите здесь в разделе "Типовые требования". Key должен быть назначаемым.

Кроме того, вы можете легко проверить это:

struct tester {
  tester(int value) : value(value) { }
  tester(const tester& t) : value(t.value) {
    std::cout << "Copy construction!" << std::endl;
  }
  int value;
};

// In order to use tester with a set:
bool operator < (const tester& t, const tester& t2) {
  return t.value < t2.value;
}

int main() {
    tester t(2);

    std::vector<tester> v;
    v.push_back(t);

    std::set<tester> s;
    s.insert(t);
}

Вы всегда увидите Copy construction!.

Если вы действительно хотите сохранить что-то вроде ссылки на объект, вы можете хранить указатели на эти объекты:

tester* t = new tester(10);
{
    std::set<tester*> s;
    s.insert(t);
    // do something awesome with s
} // here s goes out of scope just as well the contained objects
  // i.e. the *pointers* to tester objects. The referenced objects
  // still exist and thus we must delete them at the end of the day:
delete t;

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

Или вы можете использовать умные указатели, такие как boost::shared_ptr:

{
    std::set< boost::shared_ptr<tester> > s;
    s.insert(boost::shared_ptr<tester>(new tester(20)));
    // do something awesome with your set
} // here s goes out of scope and destructs all its contents,
  // i.e. the smart_ptr<tester> objects. But this doesn't mean
  // the referenced objects will be deleted.

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

Да, и кстати: Никогда не используйте std::auto_ptr s в качестве элементов в стандартных контейнерах. Их странная семантика копирования несовместима с тем, как контейнеры хранят свои данные и управляют ими, и как стандартные алгоритмы манипулируют ими. Я уверен, что в StackOverflow есть много вопросов, касающихся этой нестабильной проблемы.

1 голос
/ 26 февраля 2011

std::set скопирует вставленный элемент.

0 голосов
/ 26 февраля 2011
int *a;     
*a=new int(1);

Этот код неверен, поскольку вы пытаетесь использовать значение, хранящееся по адресу a, что является мусором.

И каждый stl содержит copy элементов, если вы не используете move семантикус insert () и push_back (), принимающими rvalue ссылки в C ++ 0x.

0 голосов
/ 26 февраля 2011

Вы сохраняете указатели в наборе.

Объект, на который указывает указатель, не копируется.
Таким образом, после вызова delete указатель в наборе недействителен.

Примечание: Вы, вероятно, хотите просто сохранить целые числа.

int a(1);
set<int>  s;
s.insert(a); // pushes 1 into the set
s.insert(2); // pushes 2 into the set.

Пара других примечаний:

  • Будьте осторожны с подчеркиванием в начале имен идентификаторов.
  • Использованиеумные указатели для хранения указателей.

Ptr:

 std::auto_ptr<int>  a(new int(1));
 set<int*>           s;
 s.insert(a.release());

 // Note. Set now holds a RAW pointer that you should delete before the set goes away.
 //       Or convert into a boost::ptr_set<int> so it takes ownership of the pointer.
...