0

I want a map to hold an object and be responsible for its deletion either when the map comes out of scope or explicitly when 'erase' is called for one of its member objects.

using std::court;
struct A {
    int x;
    char y;
    A(int z,char c): x(z),y(c){}
    ~A() { cout<<"destructor x:"<<x<<std::endl;}
};

int main() {
  std::map<int,A> m;
  std::pair<std::map<int,A>::iterator,bool> ret;
  cout<<"Hello start"<<std::endl;
  char c='f';
  ret=m.insert(std::pair<int,A>(5,A(8,c)));
  if (ret.second) {
     cout<<"Element inserted"<<std::endl;
     if (m.erase(5)==1)
        cout<<"Element erased"<<std::endl;
  }
return 0;
}

However, the above code will call the destructor for A several times. Clearly a lot of copying is taken place with temporary variables that are going out of scope. There must be a more efficient way. I consider using emplace like

m.emplace(5,8,c);

But that is not possible since emplace for map only takes two parameters. What am I doing wrong?

user2304458
  • 363
  • 1
  • 2
  • 11
  • If the 1st argument is `std::piecewise_construct`, the 2nd and 3rd arguments will be tuples containing the arguments to forward directly to the constructor of the contained value type. Why do you think only 2 arguments are available? What have you tried, and how did it fail? – underscore_d Jun 03 '20 at 16:12
  • For the other copies, (a) copy/move elision is a thing, and (b) if it's really so expensive that you can't afford ever to even slightly risk copying, then allocate it via a `unique_ptr` and `std::move()` that into `map.push_back()` - but you don't need to do that unless you can prove that you do need to do it ;-) – underscore_d Jun 03 '20 at 16:13
  • alt: [Calling std::map::emplace() and avoiding unnecessary constructions](https://stackoverflow.com/questions/20830349/calling-stdmapemplace-and-avoiding-unnecessary-constructions#comment31241611_20830492) – underscore_d Jun 03 '20 at 16:14
  • Yes, your links really clarified many things for me. The danger of using temporary objects is that what if the destructor deallocates dynamically allocated memory and you therefore only want it to happen once. But again that would be a bad design. – user2304458 Jun 03 '20 at 16:19
  • If the class does own dynamically allocated memory, it should null the pointer to it after deletion, so that subsequent attempts to delete/free will be no-ops. So, with proper coding, there's no problem. The pointer will be moved from temporary to temporary, nulled after moving in expiring instances so they don't delete it, and only deleted when the final instance goes out of scope. If you use an `std::unique_ptr`, you won't need to think about any of this, as it just does the right thing by default for you. – underscore_d Jun 03 '20 at 16:22

0 Answers0