You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++构造/析构函数操作静态变量异常:创建对象后计数为0

Owner类静态计数变量最终为0的原因及解决方法

问题场景

我定义了Owner类用于存储所有者信息,通过静态变量amountOfOwners统计已创建的所有者总数——构造函数中对其递增,析构函数中递减。但创建3个Owner对象后,该静态变量的值最终为0。

Owner类代码

class Owner {
    std::string fullname;
    std::string inn;
    std::vector<Property*> properties;
    int amountOfProperty;
  
public:
    static int amountOfOwners;

    Owner(const std::string& fullname, const std::string& inn);
    ~Owner();

    void addProperty(Property *p);
    void removeProperty(const Property* p);
};

Owner::Owner(const std::string& fullname, const std::string& inn) {
    this->fullname = fullname;
    this->inn = inn;
    amountOfProperty = 0;
    amountOfOwners++;
}

Owner::~Owner() {
    amountOfOwners--;
}

void Owner::addProperty(Property* p) {
    properties.push_back(p);
    amountOfProperty++;
}

void Owner::removeProperty(const Property* property) {
    auto it = std::find(properties.begin(), properties.end(), property);
    if (it != properties.end()) {
        properties.erase(it);
        amountOfProperty--;
    }
}

main函数代码

#include <iostream>
#include "Property.h"
#include "Appartment.h"
#include "Car.h"
#include "CountryHouse.h"
#include "Owner.h"

using namespace std;

int Owner::amountOfOwners = 0;

int main()
{
    std::vector<Owner> owners;
    char choice;

    Owner owner1("John Doe", "123456789012");
    owner1.addProperty(new Appartment(100000, 80));
    owner1.addProperty(new Car(50000, 200));
    owner1.addProperty(new CountryHouse(200000, 50));

    Owner owner2("Jane Smith", "987654321098");
    owner2.addProperty(new Appartment(150000, 100));
    owner2.addProperty(new Car(60000, 250));
    owner2.addProperty(new CountryHouse(300000, 70));

    Owner owner3("Mike Johnson", "456789012345");
    owner3.addProperty(new Appartment(120000, 90));
    owner3.addProperty(new Car(55000, 220));
    owner3.addProperty(new CountryHouse(250000, 60));

    owners.push_back(owner1);
    owners.push_back(owner2);
    owners.push_back(owner3);

    cout << Owner::amountOfOwners;
    return 0;
}

原因分析

问题核心在于默认拷贝构造未处理静态计数,且vector扩容时会销毁旧的拷贝对象:

  1. 创建owner1、owner2、owner3三个栈对象,每个对象构造时amountOfOwners递增,此时计数为3。
  2. 执行owners.push_back(owner1):vector初始为空,分配容量1,通过默认拷贝构造创建owner1的副本存入vector——但未重载拷贝构造函数,副本构造不会触发amountOfOwners递增,计数仍为3。
  3. 执行owners.push_back(owner2):vector容量不足触发扩容:
    • 销毁vector中已有的1个拷贝对象,触发析构函数,amountOfOwners减1变为2;
    • 分配新空间,拷贝原有的1个对象和owner2的副本,拷贝过程未递增计数,计数保持2。
  4. 执行owners.push_back(owner3):vector再次扩容:
    • 销毁vector中已有的2个拷贝对象,触发两次析构,amountOfOwners减2变为0;
    • 分配新空间,拷贝原有的2个对象和owner3的副本,拷贝仍未递增计数,计数保持0。
  5. 此时执行输出语句,得到的amountOfOwners即为0。

解决方案

思路一:禁用拷贝,使用原地构造或移动语义

避免对象拷贝,直接在vector中构造Owner对象,或使用移动语义转移所有权,消除不必要的拷贝和销毁:

// 在Owner类中禁用拷贝构造和拷贝赋值运算符(C++11及以上)
class Owner {
    // ... 原有成员 ...
public:
    // ... 原有成员 ...
    Owner(const Owner&) = delete;
    Owner& operator=(const Owner&) = delete;
    // 可选:启用移动构造和移动赋值
    Owner(Owner&&) = default;
    Owner& operator=(Owner&&) = default;
};

// 修改main函数,直接在vector中构造对象
int main() {
    std::vector<Owner> owners;

    // 使用emplace_back直接在vector内存中构造对象,避免拷贝
    owners.emplace_back("John Doe", "123456789012");
    owners.back().addProperty(new Appartment(100000, 80));
    owners.back().addProperty(new Car(50000, 200));
    owners.back().addProperty(new CountryHouse(200000, 50));

    owners.emplace_back("Jane Smith", "987654321098");
    owners.back().addProperty(new Appartment(150000, 100));
    owners.back().addProperty(new Car(60000, 250));
    owners.back().addProperty(new CountryHouse(300000, 70));

    owners.emplace_back("Mike Johnson", "456789012345");
    owners.back().addProperty(new Appartment(120000, 90));
    owners.back().addProperty(new Car(55000, 220));
    owners.back().addProperty(new CountryHouse(250000, 60));

    cout << Owner::amountOfOwners; // 此时输出3
    return 0;
}

思路二:重载拷贝构造和拷贝赋值,处理静态计数

若必须保留拷贝功能,需重载拷贝构造函数同步更新静态计数,同时处理properties指针的深拷贝(避免重复释放内存):

// 重载拷贝构造函数
Owner::Owner(const Owner& other) {
    this->fullname = other.fullname;
    this->inn = other.inn;
    this->amountOfProperty = other.amountOfProperty;
    // 深拷贝properties中的指针,需为Property类添加clone虚函数
    for (auto* p : other.properties) {
        this->properties.push_back(p->clone());
    }
    amountOfOwners++; // 拷贝构造时递增计数
}

// 重载拷贝赋值运算符
Owner& Owner::operator=(const Owner& other) {
    if (this != &other) {
        // 先释放当前对象的properties内存
        for (auto* p : this->properties) {
            delete p;
        }
        this->properties.clear();

        // 拷贝成员变量
        this->fullname = other.fullname;
        this->inn = other.inn;
        this->amountOfProperty = other.amountOfProperty;
        // 深拷贝properties
        for (auto* p : other.properties) {
            this->properties.push_back(p->clone());
        }
    }
    return *this;
}

// 修改析构函数,释放properties内存
Owner::~Owner() {
    for (auto* p : properties) {
        delete p;
    }
    amountOfOwners--;
}

注:需为Property类及其子类添加clone虚函数实现深拷贝,否则会引发指针悬挂和重复释放的未定义行为。

内容的提问来源于stack exchange,提问作者etmeow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 08:27:36