在很多情况下,都在使用队列,队列可能增长到数百个。不幸的是,如果有必要的话,没有一个解决队列空的解决方案。我想知道是否使用作用域队列进行交换,然后销毁作用域队列,是否破坏了任何内存分配/管理规则?
以下代码段是我建议的示例。如果长时间使用,似乎工作正常,不确定结果。
#include <cstdlib>
#include <iostream>
#include <queue>
int
main()
{
std::queue<int> foo;
foo.push(10);
foo.push(20);
foo.push(30);
std::cout << "size of before foo: " << foo.size() << '\n';
{
std::queue<int> bar;
swap(foo, bar);
}
std::cout << "size of after foo: " << foo.size() << '\n';
return 0;
}
答案 0 :(得分:5)
您的代码很好。 swap
将使foo
成为默认构造的std::queue
,并且当bar
在作用域末尾被销毁时,它将释放foo
正在使用的内存。由于您没有使用new
或delete
,因此没有问题,因为std::queue
“做正确的事”(RAII类型是一件很棒的事)
您已成功完成
std::queue<int>{std::move(foo)}; // move foo into a temporary that is immediately destroyed to release the storage
但是您的方法为您提供了foo
状态的更强有力的保证。您的方法将foo
保留为默认的构造状态,而上述方法将其保留为有效但未指定的状态。
另一种选择是使用Is there a way to access the underlying container of STL container adaptors?中提供的解决方案之一来从foo
获取基础容器并对其进行调用clear。看起来像
#include <cstdlib>
#include <iostream>
#include <queue>
// function from https://stackoverflow.com/a/29325258/4342498 by jxh: https://stackoverflow.com/users/315052
template <class ADAPTER>
typename ADAPTER::container_type & get_container (ADAPTER &a)
{
struct hack : ADAPTER {
static typename ADAPTER::container_type & get (ADAPTER &a) {
return a.*&hack::c;
}
};
return hack::get(a);
}
int main()
{
std::queue<int> foo;
foo.push(10);
foo.push(20);
foo.push(30);
std::cout << "size of before foo: " << foo.size() << '\n';
get_container(foo).clear();
std::cout << "size of after foo: " << foo.size() << '\n';
return 0;
}
答案 1 :(得分:2)
这不仅是完全安全的,而且还是容器的移动构造函数通常如何工作的方式:通过与寿命短(或至少即将被破坏)的另一个对象交换,然后让另一个对象死亡。然后,析构函数会尽快为您执行所有数据清除。 (此处可解决缺少clear()
成员函数的问题。)
我认为是否需要一次“清除”操作,而我真的想使用队列(例如,像您所说的那样强制FIFO),那么我会做同样的事情。
尽管如果您可以让旧容器超出范围并切换到使用新声明的容器,那就更好了。
答案 2 :(得分:1)
不应违反任何规则,但您可以这样做
e.g 1, 2, 3, 4, ...17
答案 3 :(得分:1)
即使长时间进行很多次也没关系。如果销毁非空队列是合法的,并且交换队列是合法的,则交换并销毁是合法的。
我想说的是,将队列(或与此相关的任何其他容器)交换到临时对象是在线程感知上下文中清理容器的首选方法:
void MyClass::Reset()
{
// ...
{
Container tmp;
{
std::scoped_lock lock(m_mutex);
tmp.swap(m_container);
}
}
// ...
}
原因是
答案 4 :(得分:1)
不需要范围:
std::queue<int>().swap(foo);
但是,否则,您的代码有效。
在这里,我们创建一个临时的空队列。然后,我们将其状态与具有大量状态的队列交换;因此foo
没有状态,临时队列具有foo
的旧状态。
然后,在语句末尾,我们销毁临时队列以及foo
的旧状态。
还有一个简短的说明适用于每种类型:
template<class T>
void clear( T& t ) {
using std::swap;
swap( static_cast<T&>(T()), t );
}
那不是普通的数据。检测我们想要对T
进行零初始化的情况非常棘手。
无法默认构造的()
对象将无法在此处编译。