Domanda

does the function set::insert saves a pointer to the element or a copy of it. meaning, can I do the following code, or I have to make sure that the pointers are not deleted?

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

I gave the example with int, but my real program uses classes that I created.

È stato utile?

Soluzione

All STL containers store a copy of the inserted data. Look here in section "Description" in the third paragraph: A Container (and std::set models a Container) owns its elements. And for more details look at the following footnote [1]. In particular for the std::set look here under the section "Type requirements". The Key must be Assignable.

Apart from that you can test this easily:

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);
}

You'll always see Copy construction!.

If you really want to store something like a reference to an object you either can store pointers to these objects:

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;

But in this case you have to take care of deleting the objects correctly and this is sometimes very difficult. For example exceptions can change the path of execution dramatically and you never reach the right delete.

Or you can use smart pointers like 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.

Now the smart pointers takes care for you and delete their referenced objects at the right time. If you copied one of the inserted smart pointers and transfered it somewhere else the commonly referenced object won't be delete until the last smart pointer referencing this object goes out of scope.

Oh and by the way: Never use std::auto_ptrs as elements in the standard containers. Their strange copy semantics aren't compatible with the way the containers are storing and managing their data and how the standard algorithms are manipulating them. I'm sure there are many questions here on StackOverflow concerning this precarious issue.

Altri suggerimenti

std::set will copy the element you insert.

You are saving pointers into the set.

The object pointed at by the pointer is not copied.
Thus after calling delete the pointer in the set is invalid.

Note: You probably want to just save integers.

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

Couple of other notes:

  • Be careful with underscores at the beginning of identifier names.
  • Use smart pointers to hold pointers.

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.
int *a;     
*a=new int(1);

This code is wrong because you try to use the value stored at address a which is a garbage.

And, every stl containers copy elements unless you use move semantics with insert() and push_back() taking rvalue references in C++0x.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top