【问题标题】:C++ trick to ensure deallocation of a vector, but compilation problems with GNU g++确保释放向量的 C++ 技巧,但 GNU g++ 的编译问题
【发布时间】:2011-11-03 12:48:20
【问题描述】:

以下代码演示了确保向量完全解除分配的技巧:

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

对此有何看法?

【问题讨论】:

  • 我的观点是,既然它即将超出范围,你应该什么都不做,让析构函数清理它。
  • 没有。不要从标准容器继承。不要冒险。
  • 这对传统的swap 技巧有何改进?另请注意,感谢shrink_to_fit,C++11 使这个问题变得不那么重要了。
  • @KerrekSB: shrink_to_fit 没有任何保证。由实现决定是否应该进行释放。真正的问题是“std::vector&lt;int&gt;().swap(v);v = std::vector&lt;int&gt;() 相比有何改进”。

标签: c++ visual-c++ g++


【解决方案1】:

这是众所周知的。释放向量内容的标准教科书技巧是:

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

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

请注意,反向不起作用:

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

因为您试图将临时对象绑定到非 const 引用,这是被禁止的。

Visual Studio 允许将此作为​​非标准扩展,但将警告级别提升到 /W3 (IIRC) 会触发“使用非标准扩展”警告。

在 C++11 中(在技术上也是在 C++03 中!),你可以简单地做

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

或者,如果您喜欢冗长(仅限 C++11),则有

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

但该标准并不能保证缩小请求是否会得到满足。

如果您确实需要,可以使用它,但请不要从标准容器继承。这不是一件安全的事情:您可能会调用错误的析构函数。

【讨论】:

  • @MagnusHoff: clear() 不会改变向量的容量,只会改变大小。没有释放内存。
  • 太棒了。这解释了它,我只是做错了。感谢亚历山大。
【解决方案2】:

您使用临时调用swap 方法,该方法不会存储在任何地方。它不能作为参考,因为从编译器的角度来看,它没有存储在任何地方。 tvector&lt;int&gt;tvector&lt;int&gt;&amp;

【讨论】:

  • 有道理,谢谢 Joachim。一定是 Visual C++ 只是更宽容一些,并将这个临时存储在某个地方?
  • 应该注意,虽然您不能对临时对象进行非 const 引用,但对临时对象的 const 引用是可以的。但在这种情况下,const 引用将不起作用,因为必须修改参数。但是,您可以采用临时的右值引用(在 C++11 中引入)来实现移动语义。
【解决方案3】:

您正在寻找this idiom 来释放向量的保留内存:

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

不允许将临时变量传递给swap,因为swap 采用非常量引用(换句话说,它需要一个可以修改的非临时变量)。 (我很惊讶 Visual C++ 接受这个代码。)

如果您使用Clang 而不是 gcc,它会尝试为您解释这一点:

test.cc:35:14:错误:不能对类型“tvector”的非 const 左值引用 绑定到“tvector”类型的临时 tv1.swap(tvector()); ^~~~~~~~~~~~~~ test.cc:22:27:注意:在此处将参数传递给参数“v” 无效交换(tvector& v){

正确版本的习语有效,因为它创建了一个变量,该变量为整个语句保持创建状态,然后传递一个非临时参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-08
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    • 2011-04-27
    • 1970-01-01
    • 2021-11-30
    相关资源
    最近更新 更多