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

C++ vector存储右值指针在main函数外初始化时失效解决方案求助

问题根源

你当前的实现将构造函数入参的地址直接存入vector,传入的右值临时对象仅在构造函数调用期间有效,构造结束后临时对象被销毁,指针自然悬空。静态实例初始化发生在main函数执行前,临时对象销毁的时机远早于你在main中访问的时机,因此会触发非法访问;而局部变量初始化时你访问print的时机在临时对象销毁前,所以刚好可以正常运行,但本质也是未定义行为。

解决方案

核心思路是根据入参的值类别区分存储策略:左值入参仅存指针不持有所有权,避免大对象拷贝;右值入参转移所有权到Parameter实例内部,延长生命周期到和实例绑定,且仅产生移动开销(大对象移动开销远低于拷贝,小对象移动无额外成本)。
修改后的实现基于C++17标准,如下:

#include <iostream>
#include <vector>
#include <memory>
#include <utility>

template <typename T>
class Parameter {
public:
    template <typename... Args>
    Parameter(Args&&... args) {
        values.reserve(sizeof...(args));
        owned_values.reserve(sizeof...(args));
        (process_arg(std::forward<Args>(args)), ...);
    }

    void print() const {
        for (auto value : values) {
            std::cout << *value << "\n";
        }
        std::cout << "\n";
    }
    
    // 保留对外的values访问接口,和原有代码逻辑兼容
    std::vector<T*> values;
private:
    template <typename U>
    void process_arg(U&& arg) {
        if constexpr (std::is_rvalue_reference_v<U&&>) {
            // 右值入参,转移所有权到内部存储
            owned_values.emplace_back(std::make_unique<T>(std::forward<U>(arg)));
            values.push_back(owned_values.back().get());
        } else {
            // 左值入参,仅存指针,无拷贝开销
            values.push_back(&arg);
        }
    }

    std::vector<std::unique_ptr<T>> owned_values; // 持有右值入参的所有权
};

class Strategy {
public:
    static Parameter<int>   parameter1;
    static Parameter<int>   parameter2;
};

Parameter<int>  Strategy::parameter1(10, 20, 30);
Parameter<int>  Strategy::parameter2(50, 60, 70);

int main() {
    // 静态实例现在可以正常访问
    Strategy::parameter1.print();
    Strategy::parameter2.print();

    // 局部实例也可以正常运行
    Parameter   parameterA(100, 200);
    Parameter   parameterB(500, 600);
    parameterA.print();
    parameterB.print();

    // 大对象左值场景测试,无拷贝开销
    struct BigObj { int data[1024]; int val; };
    BigObj obj{{}, 123};
    Parameter<BigObj> p(obj, BigObj{{}, 456});
    std::cout << p.values[0]->val << "\n"; // 直接使用外部obj的指针,无拷贝
    std::cout << p.values[1]->val << "\n"; // 右值BigObj移动到内部存储,无拷贝
}

如果需要兼容C++11,仅需将参数包的折叠表达式替换为递归构造、或者初始化列表展开的逻辑即可。

注意事项

  1. 使用左值入参时,你需要自行保证左值的生命周期长于Parameter实例,避免左值提前销毁导致的指针悬空。
  2. 针对int、bool等轻量类型,可额外添加小对象优化逻辑:当T是可平凡拷贝且大小小于等于指针大小时,直接在vector中存值,避免堆分配开销,进一步提升性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 08:27:03