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

C++中使用vector传递任意数量参数时避免指针的方法

避免传递带析构函数的C++对象时的重复析构(无需指针)

当然有办法不用指针解决这个问题!你遇到的核心问题是直接传递对象会触发拷贝构造——vector里存储的是原对象的副本,当vector销毁时,这些副本会调用析构函数,加上原对象本身的析构,就出现了两次析构的情况。要解决这个问题,核心思路是传递引用而非拷贝对象,这样容器里只保存对原对象的引用,不会产生额外的对象实例。

下面给你几个实用的方案:

方案1:使用std::reference_wrapper包装引用

C++的标准容器不能直接存储引用(因为引用不支持赋值操作,不符合容器元素的要求),但可以用std::reference_wrapper来包装引用——它可以像引用一样使用,同时满足容器的可赋值要求。

修改你的代码如下:

#include<iostream>
#include<vector>
#include<functional> // 引入std::reference_wrapper和std::ref

class integer {
private:
    int data;
public:
    integer(int value = 0): data(value) {}
    ~integer() { 
        // 可以加个打印验证析构次数
        std::cout << "Destructing integer with value: " << data << std::endl; 
    }
    void increase() { data++; }
    friend std::ostream& operator<<(std::ostream& os, const integer& x);
};

std::ostream& operator<<(std::ostream& os, const integer& x) {
    os << x.data;
    return os;
}

// 修改参数为vector<reference_wrapper<integer>>
void foo(std::vector<std::reference_wrapper<integer>> vec) {
    for (auto& ref : vec) {
        ref.increase(); // reference_wrapper重载了operator(),可直接调用成员函数
    }
}

int main() {
    integer x1(3);
    integer x2(4);
    integer x3(5);
    std::cout << x1 << " " << x2 << " " << x3 << std::endl;
    
    // 用std::ref包装对象,传入vector
    foo({std::ref(x1), std::ref(x2), std::ref(x3)});
    
    std::cout << x1 << " " << x2 << " " << x3 << std::endl;
    return 0;
}

运行这段代码你会发现,每个integer对象只会被析构一次(在main函数结束时),完全避免了重复析构的问题。

方案2:使用模板参数包(更灵活,无需vector)

如果你的函数不需要存储这些对象,只是要对它们执行操作,那可以直接用模板参数包接受任意数量的对象引用,连vector都不用:

#include<iostream>

class integer {
private:
    int data;
public:
    integer(int value = 0): data(value) {}
    ~integer() { 
        std::cout << "Destructing integer with value: " << data << std::endl; 
    }
    void increase() { data++; }
    friend std::ostream& operator<<(std::ostream& os, const integer& x);
};

std::ostream& operator<<(std::ostream& os, const integer& x) {
    os << x.data;
    return os;
}

// 模板函数,接受任意数量的integer引用
template<typename... Args>
void foo(Args&... args) {
    // 折叠表达式,对每个参数调用increase()
    (args.increase(), ...);
}

int main() {
    integer x1(3);
    integer x2(4);
    integer x3(5);
    std::cout << x1 << " " << x2 << " " << x3 << std::endl;
    
    // 直接传递对象引用,无需任何包装
    foo(x1, x2, x3);
    
    std::cout << x1 << " " << x2 << " " << x3 << std::endl;
    return 0;
}

这个方案更简洁,完全避免了容器的使用,效率更高,同时也不会产生任何额外的对象拷贝。

关键注意点

无论用哪种方案,都要确保原对象的生命周期长于函数调用的生命周期——比如在你的示例中,x1、x2、x3是main函数的局部变量,在foo调用结束后依然存在,所以不会有悬空引用/指针的问题。如果是动态分配的对象,也要确保在函数使用期间对象不会被销毁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:02:22