комплексный тип параметра шаблона для набора C ++ STL - PullRequest
0 голосов
/ 27 августа 2011

Я реализую набор STL со сложным типом параметра шаблона.Вставляя в набор, я хочу, чтобы набор использовал оператор меньше, чем я определил для моего типа.Я также хочу минимизировать количество экземпляров объектов моего типа.Кажется, у меня не может быть обоих.

У меня есть два минимальных примера ниже, каждый использует один и тот же класс C ++.

#include <iostream>
#include <set>

using namespace std;

class Foo {
    public:
        Foo(int z);
        Foo(const Foo &z);
        bool operator<(const Foo &rhs) const;
        int a;
};

Foo::Foo(int z)
{
    cout << "cons" << endl;
    a = z;
}

Foo::Foo(const Foo &z)
{
    cout << "copy cons" << endl;
    a = z.a;
}

bool
Foo::operator<(const Foo &rhs) const
{
    cout << "less than" << endl;
    return a < rhs.a;
}

Вот мой первый метод main ():

int
main(void)
{
    set<Foo> s;

    s.insert(*new Foo(1));
    s.insert(*new Foo(2));
    s.insert(*new Foo(1));

    cout << "size: " << s.size() << endl;

    return 0;
}

Это здорово, потому что он использует меньше, чем я определил для моего класса, и, следовательно, размер набора правильно равен двум.Но это плохо, потому что каждая вставка в набор требует создания двух объектов (конструктор, конструктор копирования).

$ ./a.out
cons
copy cons
cons
less than
less than
less than
copy cons
cons
less than
less than
less than
size: 2

Вот мой второй метод main ():

int
main(void)
{
    set<Foo *> s;

    s.insert(new Foo(1));
    s.insert(new Foo(2));
    s.insert(new Foo(1));

    cout << "size: " << s.size() << endl;

    return 0;
}

Это здоровопотому что для вставки требуется только один экземпляр объекта.Но это плохо, потому что это действительно набор указателей, и, таким образом, уникальность членов набора не учитывается в моем типе.

$ ./a.out
cons
cons
cons
size: 3

Я надеюсь, что мне не хватает некоторой информации,Могу ли я иметь как минимальные экземпляры объектов, так и соответствующую сортировку?

Ответы [ 3 ]

1 голос
/ 27 августа 2011

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

int main()
{
    set<Foo> s;

    s.insert(Foo(1));
    s.insert(Foo(2));
    s.insert(Foo(1));

    cout << "size: " << s.size() << endl;

    return 0;
}

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

int main()
{
    set<Foo> s;

    Foo temp(1);
    s.insert(temp);
    temp.a = 2;
    s.insert(temp);
    temp.a = 1;
    s.insert(temp);

    cout << "size: " << s.size() << endl;

    return 0;
}

Вывод этого фрагмента (через ideone):

cons
copy cons 
less than
less than
less than
copy cons
less than
less than
less than
size: 2

Как правило, я бы предпочел хранить фактические объекты в set<Foo>, а не в указателях на объекты в set<Foo*>, поскольку не может быть проблем с владением объектом (кому / когда new и delete нужно ), общий объем выделяемой памяти меньше (для N элементов, которые вам нужны N*sizeof(Foo), а не N*(sizeof(Foo) + sizeof(Foo*)) байт), и доступ к данным может обычно быть более быстрым (поскольку существует без дополнительной косвенной указки).

Надеюсь, это поможет.

1 голос
/ 27 августа 2011

Вы получаете копию от этого: *new Foo(1).

Создайте эту структуру:

template<typename T>
struct PtrLess
{
    bool operator()(const T *a, const T *b) const
    {
        return *a < *b;
    }
};

Сделайте карту похожей на set<Foo*, PtrLess<Foo>> s;, а затем добавьте Foo как s.insert(new Foo(1));Обратите внимание на *

В противном случае, когда карта создает контейнер для элемента Foo, поскольку он расположен в определении контейнеров foo, карта должна скопировать предоставленное значение во внутренний Foo.объект.

0 голосов
/ 27 августа 2011

Это расширение к @ Mranz's answer . Вместо того, чтобы иметь дело с необработанными указателями, поместите указатели в std::unique_ptr

#include <memory>

using namespace std;

template<typename T>
struct PtrLess
{
    bool operator()(const T& a, const T& b) const
    {
        return *a < *b;
    }
};


int
main(void)
{
    set<unique_ptr<Foo>, PtrLess<unique_ptr<Foo>>> s;

    s.insert(unique_ptr<Foo>(new Foo(1)));
    s.insert(unique_ptr<Foo>(new Foo(2)));
    s.insert(unique_ptr<Foo>(new Foo(1)));

    cout << "size: " << s.size() << endl;

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...