c++ - 更改保持原始指针指向其字段的对象的地址

标签 c++ c++14 move raw-pointer memory-reallocation

我想重新分配一个具有自引用的类,名为CarJoker
“重新分配”在这里的意思是=改变一个对象的地址。

此技术对于使 CarJoker 的每个实例都存在于可调整大小的连续数组中是必要的,例如池。

我考虑使用 std::move,但它不能以我希望的方式 move CarJoker::wheels
( MCVE )

#include <vector>
#include <iostream>
#include <string>
struct Wheel{
    void setBlade(){}
    void setTwinkle(){}
};
struct CarJoker{
    Wheel wa;
    Wheel wb;
    Wheel wc;
    std::vector<Wheel*> wheels;
    float hp=5;
    CarJoker(){
        wheels.push_back(&wa);
        wheels.push_back(&wb);
        wheels.push_back(&wc);
    }
    void wow(){
        //v want to apply something to every "wheel"
        for(auto wheel:wheels){
            wheel->setBlade();
        }
        //v want to apply something to some certain "wheel"
        wa.setTwinkle();
    }
};

int main(){
    CarJoker car1;
    CarJoker car2=std::move(car1);
    std::cout<<"want to 1 : "<<(car2.wheels[0]== &car2.wa)<<std::endl;
}

使用std::movecar2.wheels[0] 指向&car1.wa 而不是&car2.wa如我所愿。
我知道原因,但这不是我的目标,而且我不知道修复它的优雅方法。

我糟糕的解决方法

这是一个不优雅的方式(MCVE):-

struct CarJoker{
    Wheel wa;
    Wheel wb;
    Wheel wc;
    std::vector<Wheel*> wheels;
    float hp=5;
    CarJoker(){
        reIni();  //: CHANGE (call a new function)
    }
    void reIni(){ //: CHANGE (create a new function)
        wheels.clear();
        wheels.push_back(&wa);
        wheels.push_back(&wb);
        wheels.push_back(&wc);
    }
    void wow(){
        //v want to apply something to every "wheel"
        for(auto wheel:wheels){
            wheel->setBlade();
        }
        //v want to apply something to some certain "wheel"
        wa.setTwinkle();
    }
};
int main(){
    CarJoker car1;
    CarJoker car2=std::move(car1);
    car2.reIni(); //: CHANGE (call a new function)
    std::cout<<"want to 1 : "<<(car2.wheels[0]== &car2.wa)<<std::endl;
}

缺点:-
1. 很脏。
2. 我必须为池中存在此类症状的每个类创建一个特殊名称函数 (reIni())。我的池也必须识别该函数(例如使用模板或虚拟函数注册)。

我糟糕的解决方法 2

 struct CarJoker{
    Wheel wa;
    Wheel wb;
    Wheel wc;
    std::vector<Wheel*> getWheels(){  //use this instead of "wheels"
        std::vector<Wheel*> re;
        re.push_back(&wa);
        re.push_back(&wb);
        re.push_back(&wc);
        return re;
    }
    ....
 }

我会工作,但我觉得这样的解决方法太疯狂了。
该限制增加了编码人员的陷阱。

如果 wheels 碰巧需要缓存计算量大的结果,现在经常调用 getWheels() 会很昂贵。

最佳答案

您不需要 reIni()方法。您需要添加的是:

  • 复制构造函数和 move 构造函数都初始化 wheels成员的方式与默认构造函数相同。

  • 不复制/move wheels 的复制赋值运算符和 move 赋值运算符成员。

试试这个:

struct CarJoker{
    Wheel wa;
    Wheel wb;
    Wheel wc;
    std::vector<Wheel*> wheels;
    float hp = 5;

    CarJoker(){
        wheels.push_back(&wa);
        wheels.push_back(&wb);
        wheels.push_back(&wc);
    }

    CarJoker(const CarJoker &src) :
        CarJoker(),
        wa(src.wa),
        wb(src.wb),
        wc(src.wc),
        //wheels(src.wheels),
        hp(src.hp){
    }

    CarJoker(CarJoker &&src) :
        CarJoker(),
        wa(std::move(src.wa)),
        wb(std::move(src.wb)),
        wc(std::move(src.wc)),
        //wheels(std::move(src.wheels)), 
        hp(src.hp){
    }

    // copy assignment and move assignment can be
    // handled with a single implementation that
    // lets the compiler choose between the copy
    // constructor and move constructor as needed...
    CarJoker& operator=(CarJoker rhs){
        wa = std::move(rhs.wa);
        wb = std::move(rhs.wb);
        wc = std::move(rhs.wc);
        wheels = std::move(rhs.wheels);
        hp = rhs.hp;
        return *this;
    }

    ...
}; 

话虽如此,您真的不应该一开始就使用自引用字段。单std::array<Wheel, 3>字段比 3 Wheel 更有意义字段和一个 std::vector<Wheel*>领域,避免了这整个问题。

struct CarJoker{
    std::array<Wheel, 3> wheels;
    float hp = 5;

    CarJoker() = default;
    CarJoker(const CarJoker&) = default;
    CarJoker(CarJoker&&) = default;
    CarJoker& operator=(const CarJoker&) = default;
    CarJoker& operator=(CarJoker&&) = default;

    Wheel& wa() { return wheels[0]; }
    const Wheel& wa() const { return wheels[0]; }

    Wheel& wb() { return wheels[1]; }
    const Wheel& wb() const { return wheels[1]; }

    Wheel& wc() { return wheels[2]; }
    const Wheel& wc() const { return wheels[2]; }

    void wow(){
        //v want to apply something to every "wheel"
        for(auto &wheel : wheels){
            wheel.setBlade();
        }

        //v want to apply something to some certain "wheel"
        wa().setTwinkle();
    }
};

关于c++ - 更改保持原始指针指向其字段的对象的地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58296788/

相关文章:

c++ - LoadLibrary 与将二进制 dll 加载到进程中?

C++ 使用关系运算符比较字符串

c++ - 从成员函数返回一个只能 move 的对象

c++ move 窗口而不改变其大小

c++ - 在 C++ Builder 中编译 Boost 库时的警告

c++ - sprintf() 乱码输出

c++ - 什么是已删除函数,为什么只有我传递文件的函数才被视为已删除?

c++ - 从 BOOST 或 C++14 类中删除 ACE_Singleton 和其他一些 Singleton 类

c++ - 使用变量的类型作为模板参数

Windows批处理命令 move 目录中的所有文件夹,但有异常(exception)