Трюк C ++ для обеспечения освобождения вектора, но проблемы компиляции с GNU g ++ - PullRequest
2 голосов
/ 03 ноября 2011

В следующем коде демонстрируется прием, обеспечивающий полное освобождение вектора:

#include <vector>

using namespace std;

template<typename T>
class tvector : public vector<T>
{
    public:
    typedef vector<T> base;
    void swap(tvector<T>& v) {
        // do some other stuff, but omitted here.
        base::swap(v); }
};

int main()
{
    tvector<int> tv1;
    // imagine filling tv1 with loads of stuff, use it for something...

    // now by swapping with a temporary declaration of an empty tvector that should
    // go out of scope at the end of the line, we get all memory used by tv1 returned
    // to the heap
    tv1.swap(tvector<int>());
}

Хорошо, это работает с использованием Visual C ++ (cl.exe), но с использованием GNU g ++ не компилируется с этой ошибкой:

test.cpp: In function ‘int main()’:
test.cpp:18:28: error: no matching function for call to ‘tvector<int>::swap(tvector<int>)’
test.cpp:10:7: note: candidate is: void tvector<T>::swap(tvector<T>&) [with T = int]

Это ошибка в g ++, или мой код действительно неверный код C ++?

Мой обходной путь для этого трюка освобождения с использованием g ++ заключается в следующем:

int main()
{
    tvector<int> tv1;
    {
        tvector<int> t;
        tv1.swap(t);
    }
}

Есть мнения по этому поводу?

Ответы [ 3 ]

12 голосов
/ 03 ноября 2011

Это все хорошо известно. Стандартный трюк из учебника для освобождения содержимого вектора:

std::vector<int> v;
// Do stuff with v

std::vector<int>().swap(v); // clears v

Обратите внимание, что обратное не работает:

v.swap(std::vector<int>()); // compile time error

потому что вы пытаетесь привязать временную ссылку к неконстантной ссылке, что запрещено.

Visual Studio допускает это как нестандартное расширение, но повышение уровня предупреждений до / W3 (IIRC) вызывает предупреждение "используется нестандартное расширение".

В C ++ 11 (и технически в C ++ 03 тоже!) Вы можете просто сделать

v = std::vector<int>();

или, если вы многословны (только C ++ 11), есть

v.clear(); // or v.resize(0);
v.shrink_to_fit(); 

но стандарт ничего не гарантирует о том, будет ли выполнен запрос на сокращение.

Вы можете использовать это, если вам действительно нужно, но, пожалуйста, не наследуйте от стандартных контейнеров . Это небезопасно: вы рискуете вызвать не тот деструктор.

3 голосов
/ 03 ноября 2011

Вы вызываете метод swap с временным значением, которое нигде не сохраняется. Это не может быть взято как ссылка, потому что с точки зрения компиляторов оно нигде не хранится. tvector<int> против tvector<int>&.

2 голосов
/ 03 ноября 2011

Вы ищете эту идиому для освобождения зарезервированной памяти вектора:

tvector<int>().swap(tv1);

Передача временной переменной в swap недопустима, поскольку swap занимаетнеконстантная ссылка (другими словами, ей нужна временная переменная, которую она может изменить).(Я удивлен, что Visual C ++ принимает этот код.)

Если вы используете Clang вместо gcc, он пытается объяснить это для вас:

test.cc:35:14: error: non-const lvalue reference to type 'tvector' cannot
      bind to a temporary of type 'tvector'
    tv1.swap(tvector());
             ^~~~~~~~~~~~~~
test.cc:22:27: note: passing argument to parameter 'v' here
    void swap(tvector& v) {

Правильная версия идиомы работает, потому что она создает переменную, которая остается созданной для всего оператора, а затем передает невременный параметр.

...