C++中的静态变量和对象寿命

Static variable and object life span in C++

本文关键字:对象 变量 静态 C++      更新时间:2023-10-16

我是C++的初学者,我理解"通过值或引用传递"、对象范围和对象实例化的基本概念,在简单示例中使用和不使用关键字"new"。问题是,当我试图解决的问题变得更加复杂时,我不知道我从简单的例子中了解到的这个理论是如何应用于由多个类组成的问题的。

我有一个PaintWidget.cpp,负责为所有车辆喷漆。

void PaintWidget::paintEvent(QPaintEvent *) {
   if (!Vehicle::GetVehicles()->empty()) {
    cout << "not null" << endl;
    QPainter painter(this);
    QPen pen1(Qt::red);
    pen1.setWidth(2);
    std::vector<Vehicle>::iterator it;
    for (it = Vehicle::GetVehicles()->begin(); it != Vehicle::GetVehicles()->end(); it++) {
        cout << "draaaaw" << endl;
        QRect rect(it->GetXcord(), it->GetYcord(), it->GetWidth(), it->GetHeight());
        cout << std::to_string(it->GetXcord()) + " " + std::to_string(it->GetYcord()) + " " + std::to_string(it->GetWidth()) + " " + std::to_string(it->GetHeight()) + " " << endl;
        painter.setPen(pen1);
        painter.drawRect(rect);
    }
} else {
    cout << "is null" << endl;
}
}

然后我有Vehicle.h

#ifndef VEHICLE_H
#define VEHICLE_H
#include <vector>
#include <map>
class Vehicle {
public:
    Vehicle();
    Vehicle(const Vehicle& orig);
    virtual ~Vehicle();
    void initVehicles();
    Vehicle createVehicle();
    static std::map<Road, int> &GetVeh_num() {
        return veh_num;
    }
    static std::vector<Vehicle> *GetVehicles() {
        return &vehicles;
    }

private:
    int xcord;
    int ycord;
    int height = 20;
    int width = 50;
    static std::vector<Vehicle> vehicles;
    static std::map<Road, int> veh_num;
};
#endif  /* VEHICLE_H */

Vehicle.cpp

#include "Vehicle.h"
#include <vector>
std::vector<Vehicle> Vehicle::vehicles;
std::map<Vehicle::Road, int> Vehicle::veh_num = {
    {Vehicle::Top, 0},
    {Vehicle::Right, 0},
    {Vehicle::Bottom, 0},
    {Vehicle::Left, 0}
};
Vehicle::Vehicle() {
}
Vehicle::Vehicle(const Vehicle& orig) {
}
Vehicle::~Vehicle() {
}

int Vehicle::GetXcord() const {
    return xcord;
}
int Vehicle::GetYcord() const {
    return ycord;
}
void Vehicle::SetXcord(int xcord) {
    this->xcord = xcord;
}
void Vehicle::SetYcord(int ycord) {
    this->ycord = ycord;
}
int Vehicle::GetHeight() const {
    return height;
}
int Vehicle::GetWidth() const {
    return width;
}
void Vehicle::initVehicles() {
    for (int i = 0; i < 5; i++) {
        Vehicle::vehicles.push_back(this->createVehicle());
    }
}
Vehicle Vehicle::createVehicle() {
    std::map<Vehicle::Road, int>::iterator it;
    Vehicle v;
    for (it = Vehicle::veh_num.begin(); it != Vehicle::veh_num.end(); it++) {
        int &vehnum = it->second;
        if (it->first == Vehicle::Road::Right) {
            int xc = 520 + vehnum * this->GetWidth() + vehnum * 5;
            int yc = 220;
            v.SetXcord(xc);
            v.SetYcord(yc);
            v.SetRoad(Vehicle::Right);
        }
    }
    return v;
}

如您所见,createVehicle返回一个新Vehicle的副本,然后将其插入静态变量Vehicles中。GetVehicles返回插入车辆的矢量指针,因为我不想返回副本。当我运行此代码时,尽管静态变量中有5个对象,但没有绘制任何对象(paintEvent被调用,字符串"draaaaw"被打印5次)。我怀疑我的物体寿命有问题,所以我换了

static std::vector<Vehicle> vehicles;

static std::vector<Vehicle*> vehicles;

当然还有来自的车辆实例化

Vehicle v;

Vehicle *v = new Vehicle();

如果我理解正确的话,它会在堆上创建一个对象。在对方法进行了所有必要的更改之后,我的代码就可以工作了(所有对象都已绘制)。我不明白的是,如果我每次都返回一份副本,这些对象什么时候被销毁,为什么会被销毁。为什么矢量车辆不是空的(我仍然有5个"重影"对象,它们不包含我之前设置的任何值)。据我所知,不建议使用new创建对象,所以第二个选项是智能指针?

谢谢:)

编辑我特意在.h和.cpp文件中省略了setter和getter,以便代码尽可能短,只包含相关信息。

我认为您的主要问题是定义了一个空的复制构造函数:

Vehicle::Vehicle(const Vehicle& orig)
{
}

这意味着,当您将Vehicle添加到容器时,会生成一个实际上并不复制任何内容的副本。你应该删除你自己的构造函数,让编译器为你做这项工作。

如果不使用指针或引用,对象的寿命将永远不会有问题。这根本不可能发生。"RAII"的整个概念是,如果变量在代码中是可访问的,那么它就是有效的。

为了测试这一点,还可以打印出车辆的坐标和尺寸。如果打印出有效的结果,那么您就知道问题出在绘制函数本身。

所以,除非需要修改对象,否则不要传递对象的指针,即使这样,也要返回引用而不是指针。只是要确保不要返回临时的引用,因为这可能会导致寿命问题。