首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何消耗对象的灵魂

如何消耗对象的灵魂
EN

Stack Overflow用户
提问于 2021-11-04 16:16:36
回答 2查看 152关注 0票数 3

我有一个可移动的类型,没有默认的构造函数,我想删除它的内部数据并销毁它们。我的想法是将其std::move为临时的,并让临时析构函数发生(以破坏内部数据),将原始的现在为空的对象抛在后面。

我得到的最接近的是一个小助手模板,它唯一的目的是销毁它的参数(这就是为什么它通过值传递,以及为什么函数的主体是空的)。(也许还有更好的方法?)然后,我调用std::move将原始对象的内部移动到一个临时对象中,这个临时值将被销毁,破坏原始内部,并使对象在将其内部部分移动到另一个对象后处于任何状态。

代码语言:javascript
复制
template <typename T>
void reset(T t) {}
};

reset(std::move(somevar));

例如,如果我有一个非常长的字符串的向量,并且我想“释放”向量中间的一个字符串所使用的内存。这不是一个完美的例子,因为字符串确实有一个无参数的构造函数,,但我的类型不是。尽管如此,这还是抓住了我尝试的动机的精神。

代码语言:javascript
复制
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]成为一个空字符串。

这个特技的重要部分是我们不需要构造空字符串。这一点很重要,因为我的可移动类型可以移动,但不能默认构造。

我尝试过的其他事情:

代码语言:javascript
复制
{ std::move(somevar); } // this doesn't work

std::move本身并不起作用,因为您必须将内容放在某个地方。

代码语言:javascript
复制
{ 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可以完成与将对象的内容移动到一个虚拟对象,然后销毁该虚拟对象,使原始对象不包含任何内容(或者移动构造函数将其保留的任何状态)相同的任务?

也许我不知道有什么明显的方法?我觉得有一些超简单的方法我只是不知道。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-11-04 16:24:50

移动不是自动的,但是非const引用是自动的,所以您可以编写

代码语言:javascript
复制
template<class T>
void dementor(T &t) {T(std::move(t));}
票数 5
EN

Stack Overflow用户

发布于 2021-12-07 00:25:57

除了@Davis Herring给出的很好的答案之外,我还将提供一些您可以使用的更多选项,而不是移动到可能工作得更好的临时选项,这会影响到您的应用程序:

1.为您的类型添加reset()方法

最简单的解决方案是将一个reset()方法添加到您的类型中,清除所有内部数据。

然后,您就不需要仅仅因为清除对象的副作用而执行移到临时的操作。

2.使用std::optional

这也是std::optional的一个很好的用例。

如果将昂贵的类包装到std::optional中,则可以通过调用.reset()随时销毁包含的值。此外,使用可选选项,您可以检查当前是否存在一个值。

这比移动到临时对象更强大,因为对可选对象调用reset()将导致销毁包含的对象。所以,不管里面是什么,它都会直接消失。

例如,对于数组情况,可以使用:

代码语言:javascript
复制
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实例的生存期。

您还可以避免移动对象的恶作剧,即:

  • 移动构造函数/移动赋值运算符可能实际上复制了一些(或全部)成员,而不是移动它们。
  • 从移出对象只需要处于有效状态,但可以是不确定的。因此,唯一需要处理移出对象的东西是:(1)销毁它或(2)将另一个对象移动(或复制)到其中。 示例: std::string a= "FOO";std::string b= "BAR";a= std::move(b);std::cout << b << std::<<::endl; 可能导致打印FOOBAR,无任何或一些随机值。(取决于移动的实现方式)

3.智能指针

如果您的对象相当大,并且您希望在堆中分配它们,那么您可以在上面的示例中使用std::optional / std::shared_ptr交换std::unique_ptr /std::shared_ptr

它们还提供了一个.reset()函数,该函数将指针重置为空状态。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69842447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档