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

向std::map赋值为何需类有无参构造函数?如何避免对象拷贝?

关于std::map与Variant类的两个技术问题

我正在研究一款开源应用的代码,已编写简化版本定位问题,现提出以下技术问询:

主问题:为何将Variant类对象赋值给std::map时,该类必须提供无参构造函数?

核心需求是将Variant类实例赋值给键类型为std::string的std::map。若移除Variant的无参构造函数,代码编译失败,错误信息指向std::map的operator[]需要可默认构造的类型。
我理解赋值时需创建对象,但疑惑:为何调用无参构造函数后,map中存储的对象仍保留原对象的属性值(如type为5而非EMPTY的0)?

子问题:如何避免临时Variant对象的不必要拷贝?

观察构造/析构调用序列发现,临时对象存在多次拷贝(析构次数多于显式构造次数):当add方法参数为值传递时,Variant析构函数被调用3次但显式构造仅2次;尝试使用std::move未改善,希望了解如何避免这些不必要的拷贝操作。


简化代码

#include <iostream>
#include <map>
#include <string>
#include <memory>

struct Data
{
public:
    Data(const void* data, size_t bytes) : bytes(bytes)
    {
        ptr = malloc(bytes);
        memcpy(ptr, data, bytes);
        std::cout << "in ctor of Data" << std::endl;
    }
    ~Data() { free(ptr); std::cout << "in dtor of Data" << std::endl; }
    void* ptr{ nullptr };
    size_t bytes;
};

struct DataStream 
{
public:
    DataStream(const std::shared_ptr<Data>& ptr, size_t size) : ptr(ptr), size(size)
    { std::cout << "in ctor of DataStream" << std::endl; }
    std::shared_ptr<Data> ptr;
    size_t size;
};

struct Variant
{
public:
    enum Type
    {
        EMPTY,
        TYPE1 = 5,
        TYPE2 = 10
    };
    ~Variant() { std::cout << "in dtor of Variant" << std::endl; }
    
    // XXX If this ctor does NOT exist, the code doesn't compile XXX
    Variant() : type(EMPTY) { std::cout << "in ctor of Variant" << std::endl; }
    
    Variant(const int& n, Type type) : n(n), type(type) {}
    Variant(const std::shared_ptr<Data>& data, Type type, size_t size) : type(type), data(std::make_shared<DataStream>(data, size))
    { std::cout << "in ctor of Variant (ptr to typed array)" << std::endl; }
    Type type;
    int n;
    std::shared_ptr<DataStream> data;
};

struct Params
{
public:
    void add(const std::string& name, const Variant& data) { params[name] = data; }
    const Variant& operator[] (const std::string& name) { return params[name]; }
    std::map<std::string, Variant> params;
};

struct Handle
{
public:
    Params params;
    void set(const std::string& name, const Variant& data) { params.add(name, data); }
};

int main()
{
    Handle* handle = new Handle();

    char data_i[3] = { 'a', 'b', 'c' };
    std::shared_ptr<Data> data = std::make_shared<Data>(data_i, 3);
    handle->set("testC", Variant(data, Variant::TYPE1, 3));
    std::cout << "use_count data " << handle->params["testC"].data->ptr.use_count() << std::endl;
    std::cout << "Variant type " << handle->params["testC"].type << std::endl;

    delete handle;

    return 0;
}

编译错误信息

test3.cpp:52:68: note: in instantiation of member function 'std::map<std::basic_string<char>, Variant>::operator[]' requested here
    void add(const std::string& name, const Variant& data) { params[name] = data; }
                                                                   ^
test3.cpp:29:8: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
struct Variant
       ^
test3.cpp:40:5: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
    Variant(const int& n, Type type) : n(n), type(type) {}
    ^
test3.cpp:41:5: note: candidate constructor not viable: requires 3 arguments, but 0 were provided
    Variant(const std::shared_ptr<Data>& data, Type type, size_t size) : type(type), data(std::make_shared<DataStream>(data, size))
    ^

构造析构输出序列

add参数为const引用时

in ctor of Data
in ctor of DataStream
in ctor of Variant (ptr to typed array)
in ctor of Variant
in dtor of Variant
use_count data 2
Variant type 5
in dtor of Variant
in dtor of Data

add参数为值传递时

in ctor of Data
in ctor of DataStream
in ctor of Variant (ptr to typed array)
in ctor of Variant
in dtor of Variant
in dtor of Variant
use_count data 2
Variant type 5
in dtor of Variant
in dtor of Data

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 17:15:53