我有一个可移动的类型,没有默认的构造函数,我想删除它的内部数据并销毁它们。我的想法是将其std::move为临时的,并让临时析构函数发生(以破坏内部数据),将原始的现在为空的对象抛在后面。
我得到的最接近的是一个小助手模板,它唯一的目的是销毁它的参数(这就是为什么它通过值传递,以及为什么函数的主体是空的)。(也许还有更好的方法?)然后,我调用std::move将原始对象的内部移动到一个临时对象中,这个临时值将被销毁,破坏原始内部,并使对象在将其内部部分移动到另一个对象后处于任何状态。
template <typename T>
void reset(T t) {}
};
reset(std::move(somevar));例如,如果我有一个非常长的字符串的向量,并且我想“释放”向量中间的一个字符串所使用的内存。这不是一个完美的例子,因为字符串确实有一个无参数的构造函数,,但我的类型不是。尽管如此,这还是抓住了我尝试的动机的精神。
std::vector<std::string> vec; // suppose I have a populated vector of strings
// Let's "reset" vec[3] to an empty string by moving it to a temp and destroying the temp
reset(std::move(vec[3]));这将vec[3]的内部元素移到reset函数的参数t中,然后,t的析构函数清理内部。这使得vec[3]成为一个空字符串。
这个特技的重要部分是我们不需要构造空字符串。这一点很重要,因为我的可移动类型可以移动,但不能默认构造。
我尝试过的其他事情:
{ std::move(somevar); } // this doesn't workstd::move本身并不起作用,因为您必须将内容放在某个地方。
{ T t = std::move(somevar); } // works but cumbersome, and I have to name `T`我只是在寻找一个可以像reset(somevar)那样调用的函数。它吞噬了某个物体的灵魂。而且std::move部分也没那么糟糕。这有点像我希望你死的授权。所以,在我看来,可以说是reset(std::move(somevar)),但它并没有完成这项工作。所以,也许还有别的功能能做我想做的事。
那么,是否有一个std::consume_soul可以完成与将对象的内容移动到一个虚拟对象,然后销毁该虚拟对象,使原始对象不包含任何内容(或者移动构造函数将其保留的任何状态)相同的任务?
也许我不知道有什么明显的方法?我觉得有一些超简单的方法我只是不知道。
发布于 2021-11-04 16:24:50
移动不是自动的,但是非const引用是自动的,所以您可以编写
template<class T>
void dementor(T &t) {T(std::move(t));}发布于 2021-12-07 00:25:57
除了@Davis Herring给出的很好的答案之外,我还将提供一些您可以使用的更多选项,而不是移动到可能工作得更好的临时选项,这会影响到您的应用程序:
1.为您的类型添加reset()方法
最简单的解决方案是将一个reset()方法添加到您的类型中,清除所有内部数据。
然后,您就不需要仅仅因为清除对象的副作用而执行移到临时的操作。
2.使用std::optional
这也是std::optional的一个很好的用例。
如果将昂贵的类包装到std::optional中,则可以通过调用.reset()随时销毁包含的值。此外,使用可选选项,您可以检查当前是否存在一个值。
这比移动到临时对象更强大,因为对可选对象调用reset()将导致销毁包含的对象。所以,不管里面是什么,它都会直接消失。
例如,对于数组情况,可以使用:
std::vector<std::optional<ExpensiveClass>> arr;
// add a new element
arr.emplace_back(std::in_place, /* constructor args for ExpensiveClass */);
// add a new (empty) element without needing a default constructor:
arr.push_back({});
// yeeting an instance out of existence
arr[0].reset();
// creating a new instance in an empty slot
arr[2].emplace(/* constructor args for ExpensiveClass */);
// checking if there's an element
if(arr[0]) { /* ... */ }
// using it
arr[0]->doSomething();这样,您就可以轻松地控制ExpensiveClass实例的生存期。
您还可以避免移动对象的恶作剧,即:
FOO,BAR,无任何或一些随机值。(取决于移动的实现方式)3.智能指针
如果您的对象相当大,并且您希望在堆中分配它们,那么您可以在上面的示例中使用std::optional / std::shared_ptr交换std::unique_ptr /std::shared_ptr。
它们还提供了一个.reset()函数,该函数将指针重置为空状态。
https://stackoverflow.com/questions/69842447
复制相似问题