C++ 如何同时使用变量和移动变量?
假设我们有以下代码:C++ 如何同时使用变量和移动变量?,c++,constructor,c++17,move,order-of-execution,C++,Constructor,C++17,Move,Order Of Execution,假设我们有以下代码: struct some_class : parent { some_class(::other_class oth) : parent(some_function(oth.some_property), std::move(oth)) {} }; 当然,在未定义的行为中,构造结果(在我的例子中崩溃),因为C++没有指定执行顺序。但是,我怎样才能在搬家前收回财产呢?我无法更改父级。创建一个辅助函数来构造父级,您可以在其中添加排序: pare
struct some_class : parent
{
some_class(::other_class oth) :
parent(some_function(oth.some_property), std::move(oth))
{}
};
当然,在未定义的行为中,构造结果(在我的例子中崩溃),因为C++没有指定执行顺序。但是,我怎样才能在搬家前收回财产呢?我无法更改父级。创建一个辅助函数来构造父级,您可以在其中添加排序:
parent make_parent(::other_class &&oth) {
auto sf = some_function(oth.some_property);
return parent(sf, std::move(oth));
}
some_class(::other_class oth) :
parent(make_parent(std::move(oth))
{}
正如您所注意到的,该问题是由于未指定的执行顺序造成的。 通过使
parent
通过右值引用而不是左值获取对象,可以消除未定义的行为。这样,它就得到了对现有对象的引用,而该对象在内存中的数据实际上不会被移动。即:
struct parent {
parent (int thing, SomeProperty && some_property) { /* Do stuff. */ }
};
在这种情况下,在oth
上执行std::move
并不重要。它的数据实际上不会移动到另一个对象中,因为parent
需要一个右值引用。因此,即使首先调用了std::move
,您的某个函数(我假设它通过const-lvalue引用获取oth
)也会有一个合适的对象来处理
这里的主要缺点是父级现在总是需要in-rvalue。因此,如果不移动它,就不能将其作为对象传递。这意味着,如果你有一个不想丢弃的对象,你首先必须显式地复制它。即:
other_class wantToKeepThis;
auto foo = parent(wantToKeepThis); // Doesn't compile.
auto foo = parent(std::move(wantToKeepThis)); // Object gone, don't want this.
auto foo = parent(other_class(wantToKeepThis)); // OK, copied, parent gets rvalue.
您可以尝试委托构造函数:
struct some_class : parent
{
some_class(::other_class oth) :
some_class(some_function(oth.some_property), std::move(oth))
{}
private:
some_class(const ::Foo& foo, ::other_class&& oth) :
parent(foo, std::move(oth))
{}
};
你甚至可以用lambda来写,我想lambda在这种情况下看起来会非常模糊。此外,您需要在代码中留出一些空间,以便对此处发生的情况进行注释。几乎可以正常工作,但如果构造函数受到保护,并且类可能不可复制或移动呢?嗯。如果我将您的答案与Darhuuk的答案合并,我将获得某个类的委托构造函数(const::Foo&Foo,::other\u class&&oth),哪一个可能是我寻求的答案?如果直接调用第二个构造函数,我会发现这会导致非常意外的行为。我会让它成为一个私有构造函数。我以为你不能修改parent
?@Dekakaruk如果你建议的编辑无法编译,那么委托构造函数会对reason@AlanBirtles我的错误,修正了。这里没有未定义的行为<代码>标准::移动
只是对右值引用的转换。罪魁祸首是parent
的构造函数中的代码。因为没有显示,所以很难知道什么可能起作用。没错,不是真的没有定义,但绝对出乎意料。根据您使用的编译器的不同,对“原始”oth
或“从”oth
移动”调用某些函数。如果其他属性
是例如std::string
,则它包含其原始值或为空。某些函数
如何处理其参数std::move
本身实际上并没有做任何事情。@Darhuuk只有当父级的构造函数按值而不是按引用获取第二个参数时,才会出现这种情况。否则,在执行父级的构造函数之前,不会发生任何问题。@walnut-True,我假设是这样的。否则这个问题就没什么意义了。我不想改变父级,但是你的想法是使用&&和Alan Birtles的构造函数委托可能是答案。