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
相关产品推荐
相关产品推荐

