重用左值和右值的代码
Re-using code for lvalues and rvalues
本文关键字:代码 更新时间:2023-10-16
假设我有一个复制构造函数。此构造函数调用一个函数层次结构,将复制的对象作为左值引用传递。
现在,我还有一个move构造函数,它基本上可以使用与复制构造函数相同的函数层次结构。这是可行的,因为我可以将rvalue参数传递给左值层次结构。
但是在层次结构的某个地方,我有一个函数,它会在左值情况下复制资源,并在右值情况下"窃取"资源。
是否有一种方法来决定,传递给该函数的左值引用是否来自右值?我想没有。或者,通常的方法是什么,当你有一个用于复制和移动结构的函数层次结构时,它们只在很少的函数中有所不同?
代码示例:
class A{
A(const A& a){
initFrom(a);
}
A(A&& a){
initFrom(a);
}
void initFrom(const A& a){
// call a hierarchy of functions, of which one of them calls initResource(const A&)
}
void initResource(const A& a){
if(a == rvalue reference){ // **** Here's the question... ****
// steal resource
this->ptr = a.ptr;
a.ptr = nullptr;
}
else{
// copy resource
this->ptr = allocate...
copy from a.ptr to this->ptr
}
}
这是一个完美转发的典型例子:
template <typename T>
A(T && t) { initFrom(std::forward<T>(a)); }
template <typename T>
void initFrom(T && t)
{
// other calls
initResource(std::forward<T>(t));
}
void initResource(A const & rhs) { /* copy from rhs */ }
void initResource(A && rhs) { /* move from rhs */ }
(似乎你应该要么能够合并initFrom
到构造函数,否则你的类可能试图做太多,你应该重构成单一责任的组件。)
这里的一种替代方法是修改initFrom
以接受"通用引用"以允许引用崩溃,然后使用std::forward
进行完美转发。然后,您可能需要重新考虑剩余的调用层次结构。
class A{
A(const A& a){
initFrom(a);
}
A(A&& a){
initFrom(a);
}
template <typename B>
void initFrom(B&& a){ // reference collapsing applies
// call a hierarchy of functions, of which one of them calls initResource(const A&)
initResource(std::forward<B>(a));
}
void initResource(A&& a){
// steal resource
this->ptr = a.ptr;
a.ptr = nullptr;
}
void initResource(const A& a){
// copy resource
this->ptr = allocate...
//copy from a.ptr to this->ptr
}
};
我认为一个更简单的替代方法是在initFrom
调用之前首先将资源"移动"到您的类中。
A(A&& a){
this->ptr = a.ptr;
a.ptr = nullptr;
initFrom(a);
}
根据您的调用层次结构和所有这些函数除了传递对象之外必须做的事情,如果您打算将对象存储在您的类中,您可能会使用另一种技术。
class A {
A(const A& a) {
initFrom(A(a)); // take a copy here
}
A(A&& a) {
initFrom(std::move(a)); // move here
}
void initFrom(A&& a) {
initResource(std::move(a)); // just pass down
}
void initResource(A&& a) {
// you already have your copy of a here that you can store completely
// or take its guts
}
这样,你只需要一次实现所有的方法(对于右值引用),无论移动还是获取副本都直接在方法调用中处理。注意,必须始终使用std::move()来传递右值引用。
相关文章:
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 此代码是否违反一个定义规则
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 为什么在这个代码结束循环中没有得到结束
- 在c代码之间共享数据的最佳方式
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值