访问结构更改值的指针属性

时间:2017-04-12 17:48:35

标签: c++11 pointers memory struct indirection

我认为我遗漏了一些关于指针的基本内容。我有以下代码:

alicat_data *data = (alicat_data*)ent.second->get_data();

if(ent.first == "AlicatA"){

    ui->ac0_P->setValue(data->pressure);
    ui->ac0_T->setValue(data->temperature);
    ui->ac0_Q->setValue(data->flow_rate);
    ui->ac0_Q0->setValue(data->mass_flow_rate);
    ui->ac0_Qsp->setValue(data->setpoint);
 }

引用定义如下的结构:

struct alicat_data : Data {

    float pressure; /** Pressure in mb */
    float temperature; /** Temperature in degC */
    float flow_rate; /** Volumetric low rate; units are defined by the model */
    float mass_flow_rate; /** Mass flow rate; units are defined by the model */
    float setpoint; /** Device setpoint (if it is a controller); units are defined by the model */
    gas gas_; /** Enum as defined above representing the gas */

    alicat_data(float p = 0, float T = 0, float Q = 0,
            float Q0 = 0, float sp = 0, gas g = Air):pressure(p),
        temperature(T), flow_rate(Q), mass_flow_rate(Q0),
        setpoint(sp), gas_(g){
        setTime();
    }


    virtual std::string serialize2ascii(){return std::to_string(pressure)
            + "\t" + std::to_string(temperature)
            + "\t" + std::to_string(flow_rate) + "\t" + std::to_string(mass_flow_rate)
            + "\t" + std::to_string(setpoint);}

};

当执行最顶层的代码时,第一个引用data->pressure正确返回,然后看起来该地址的所有内容都变为垃圾,并且在第一个引用之后返回的数据(即data->temperature等)是不正确。

我可以通过执行以下操作来解决此问题

alicat_data data_ = *data;

但不愿意这样做。我做错了什么是创造我所看到的问题?

1 个答案:

答案 0 :(得分:1)

  • 使用get_data(),您将获得指向alicat_data内存块的指针,并将其存储到可变量alicat_data *data中,即指针。
  • 使用alicat_data data_ = *data;,您将获得实例的内存块,因此您可以使用点'。'来访问其方法和属性。

您可以移除变量alicat_data data_ = *data;并使用变量alicat_data *data,如下所示:

    for (auto const &ent : alicat_map){

        alicat_data *data = (alicat_data*)ent.second->get_data();

        if(ent.first == "AlicatA"){

            ui->ac0_P->setValue(data->pressure);
            ui->ac0_T->setValue(data->temperature);
            ui->ac0_Q->setValue(data->flow_rate);
            ui->ac0_Q0->setValue(data->mass_flow_rate);
            ui->ac0_Qsp->setValue(data->setpoint);
        }
    }

更新:点击此链接查看指针理论http://www.cplusplus.com/doc/tutorial/pointers/

此外,我和你们中的一些人制作了一个节目,向你们展示你们和我的两种方式:

#include <iostream>
#include <map>

using namespace std;

struct alicat_data {

    float pressure; /** Pressure in mb */
    float temperature; /** Temperature in degC */
    float flow_rate; /** Volumetric low rate; units are defined by the model */
    float mass_flow_rate; /** Mass flow rate; units are defined by the model */
    float setpoint; /** Device setpoint (if it is a controller); units are defined by the model */

    alicat_data(float p = 0, float T = 0, float Q = 0,
        float Q0 = 0, float sp = 0) {

        pressure = p;
        temperature = T;
        flow_rate = Q;
        mass_flow_rate = Q0;
        setpoint = sp;
    }


    virtual std::string serialize2ascii() {
        return "dummy";
    }

};



int main()
{

    map<string, alicat_data *> alicat_map;

    map<string, alicat_data *>::iterator entM;


    alicat_map["AlicatA"] = new alicat_data(1.1,2.2,3.3,4.4,5.5);
    alicat_map["AlicatB"] = new alicat_data(12.1, 23.2, 34.3, 45.4, 56.5);

    //Your Way
    for (auto const &ent : alicat_map) {

        alicat_data *data = (alicat_data*)ent.second; //Get the alicat_data* (pointer) element


        if (ent.first == "AlicatA") {

            alicat_data data_ = *data;

            float pressure = data_.pressure;
            float temp = data_.temperature;
            float rate = data_.flow_rate;
            float mflowrate = data_.mass_flow_rate;
            float setpoint = data_.setpoint;
        }
    }

    //My Way
    for (entM = alicat_map.begin(); entM != alicat_map.end(); entM++)
    {
        alicat_data *data = entM->second; //Get the alicat_data* (pointer) element

        if (entM->first == "AlicatA") {

            float pressure = data->pressure;
            float temp = data->temperature;
            float rate = data->flow_rate;
            float mflowrate = data->mass_flow_rate;
            float setpoint = data->setpoint;
        }
    }

    return 0;
}

升级Apirl 13

我正在查看你的classe alicat的代码,我找到了它:

Data *alicat::get_data(){

    alicat_data* ac_data = new alicat_data(0, 0, 0, 0, 0, Air);

    alicat_data addr_data = parse_data(port->async_rw(string(1, address)));

    ac_data = &addr_data;

    return (Data*) ac_data;

}

我注意到您正在返回一个局部变量ac_data = &addr_data;的地址,该地址变量将在方法Data *alicat::get_data()完成后删除。这就是你在调用getData后得到的数据混乱的原因。

要修复它,必须避免返回局部变量,因为它们会在程序退出上下文后被销毁。返回先前使用运算符new保留的实例。在物体被摧毁的那一刻,你就会有你描述的症状。

我注意到方法alicat_data alicat::parse_data(const std::string &msg)中存在同样的问题。

更新:考虑到这一点:

我不确定你为什么会得到那个行为,但是我知道在ac_data的上下文结束但是你分配给{{1的内存'后,局部变量getData被删除了仍然存在,当你返回该局部变量的地址时,parse_data释放了它的内存(分配到堆栈而不是堆中的存储块)和这可能是你看到垃圾的原因,但当你使用return (Data*) ac_data;时,你正在拯救分配到alicat_data data_ = *data;的内存块......怎么样?这是一个很好的问题,它可以依赖于compilar,但是你可以证明它是调试的方式,并且要小心你要进入的每个内存地址:

  1. 分配到parse_data
  2. 的内存地址
  3. 地址 从parse_data`返回到parse_data的指针。
  4. 的 设置为getData的局部变量alicat_data addr_data的内存地址。本地指针的地址 从getData返回的变量alicat_data addr_data
  5. 离开getData后,比较指针的地址 getData vs你进入的指针的地址 alicat_data *data并比较地址。