Поведение контейнера std :: set во время вставки? - PullRequest
4 голосов
/ 19 июля 2011

При вставке в набор внутренний набор удаляет несколько объектов несколько раз? Я попытался вставить два объекта типа MyClass, как в следующей программе, но, к моему удивлению, он вызывает деструктор класса с первоначально вставленным значением 2 раза! Я не могу понять никакой логики за этим. Кто-нибудь может дать какую-то идею на выходе? (выделено жирным шрифтом)

#include<stdio.h>
#include<stdlib.h>
#include<set>

 using namespace std;

   struct MyClass 
   {
      double num;

      ~MyClass()
      {
         printf("Destructor called..for val: %lf\n", num);
      }
   };

   typedef int (*fun_comp)(MyClass, MyClass);   

  int
   comp(MyClass a, MyClass b)
   {
      return a.num-b.num;
   }

  int
   main()
   {
      fun_comp fptr;
      fptr = &comp;
      set<MyClass, int (*)(MyClass, MyClass)> b(fptr);

      for(int i=3; i< 5; i++)
      {
         printf("started with i: %d....\n\n", i);
         {
            MyClass m;
            m.num=i*1.134;
            b.insert(m);
            printf("Inserted val: %lf\n", m.num);
         }
         printf("ended....\n\n");
      }

      printf("Done with insert..\n");      
      return 0;
   }

Выход: началось с я: 3 ....

Вставленный вал: 3.402000

Разрушитель вызван .. для val: 3.402000

закончился ....

началось с i: 4 ....

Деструктор вызван .. для значения: 4.536000 <------- почему это освобождается перед вставкой </p>

Вызывается деструктор .. для значения: 3.402000 <------- множественный вызов деструктора для этого ценного объекта </p>

Разрушитель вызван .. для значения: 4.536000 <-------- ?? </p>

Разрушитель вызван ... для значения: 3.402000 <------ еще раз !! </p>

Вставленный val: 4.536000

Разрушитель вызван .. для val: 4.536000

закончился ....

Готово со вставкой ..

Разрушитель вызван .. для val: 3.402000

Разрушитель вызван .. для val: 4.536000

Ответы [ 3 ]

11 голосов
/ 19 июля 2011

Компаратор

int    
comp(MyClass a, MyClass b)
{
   return a.num-b.num;
}  

принимает свои параметры по значению. Это создаст дополнительные копии, которые затем будут уничтожены.

Передача по ссылке будет работать лучше.

11 голосов
/ 19 июля 2011

Измените функцию сравнения, чтобы использовать (постоянные) ссылки

int comp(const MyClass& a, const MyClass& b)
{
  return a.num-b.num;
}

Каждый раз, когда ваш компьютер вызывается, он создает копии a и b.Эти копии уничтожаются при выходе из компьютера.

4 голосов
/ 19 июля 2011

В дополнение к пунктам, указанным выше, ваша функция сравнения недопустима, поскольку она не определяет последовательный порядок значений.Если a.num = 1 и b.num = 2, то comp (a, b) имеет значение true, что означает, что a «предшествует» b, а comp (b, a) также верно, что означает, что b «предшествует» a,Это делает поведение set неопределенным.

Лучше создать оператор меньше чем для MyClass, и пусть функция сравнения по умолчанию set <> сделает свою работу: struct MyClass {double num;

  ~MyClass()
  {
     printf("Destructor called..for val: %lf\n", num);
  }
  bool operator < (const MyClass &rhs) const
  {
    return num < rhs.num;
  }
};
...
set<MyClass> b;
...