含std::map<unique_ptr>的Singleton类编译报错,请求排查原因
C++代码编译错误排查与修复
错误原因
- PersonContainer类拷贝/移动操作禁用错误:类中声明禁用拷贝/移动构造函数时,错误地将参数类型写成了
Person,而非PersonContainer。这导致编译器自动生成了默认的拷贝构造函数,而默认拷贝构造会尝试拷贝成员变量m_person_map。 - 单例实例被错误拷贝:
main函数中auto handle = PersonContainer::getInstance();语句试图拷贝单例实例(getInstance返回引用,auto推导为值类型),触发了默认拷贝构造函数的调用。而std::map中存储的std::unique_ptr不支持拷贝操作,最终导致编译失败。
修复方案
- 修正
PersonContainer类中禁用拷贝/移动操作的函数参数类型,替换为正确的PersonContainer类型。 - 将
main中的auto handle改为auto& handle,以引用方式持有单例实例,避免拷贝。 - 补充缺失的
<string>头文件,确保std::string正常编译。
修复后的完整代码
/* --------------------------------------------------------------- */ /* 头文件包含 */ #include <iostream> #include <map> #include <memory> #include <string> /* --------------------------------------------------------------- */ /* 前向声明 */ class Person; /* --------------------------------------------------------------- */ /* 类型别名定义 */ using PersonUptr = std::unique_ptr<Person>; /* --------------------------------------------------------------- */ /** @brief 用于存储记录的Person类 */ class Person { public: /** @brief 显式构造函数 */ explicit Person(const std::string& name) : m_name(name) {} /** @brief Person实例必须唯一,禁用拷贝/移动 */ Person(const Person&) = delete; Person(Person&&) = delete; Person& operator=(const Person&) = delete; Person& operator=(Person&&) = delete; /** @brief 虚析构函数 */ virtual ~Person() = default; /** @brief 返回名称/键值 */ const std::string& getName(void) const { return m_name; } private: /** @brief 类成员变量 */ std::string m_name = ""; }; /** @brief 用于存储Person实例的单例容器类 */ class PersonContainer { public: /** @brief 虚析构函数 */ virtual ~PersonContainer() = default; /** @brief 禁用拷贝/移动 - 修正参数类型 */ PersonContainer(const PersonContainer&) = delete; PersonContainer(PersonContainer&&) = delete; PersonContainer& operator=(const PersonContainer&) = delete; PersonContainer& operator=(PersonContainer&&) = delete; /** @brief 获取单例实例 */ static PersonContainer& getInstance(void) { static PersonContainer container; return container; } /** @brief 向map中添加Person的unique_ptr */ void addPerson(PersonUptr&& person) { /** FIXME 检查重复添加 */ m_person_map.insert({person->getName(), std::move(person)}); } private: /** @brief 单例私有构造函数 */ PersonContainer() = default; /** @brief 类成员变量 */ std::map<std::string, PersonUptr> m_person_map; }; /** @brief 测试代码 */ int main(void) { /** 获取容器实例 - 使用引用避免拷贝 */ auto& handle = PersonContainer::getInstance(); return 0; }
错误信息翻译
从personal-record.cc:4包含的文件中: 从/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/iostream:43包含的文件中: 从/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/ios:222包含的文件中: 从/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__locale:15包含的文件中: 从/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/shared_ptr.h:22包含的文件中: 从/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/allocation_guard.h:15包含的文件中: /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/allocator_traits.h:304:9: 错误:找不到匹配的‘construct_at’调用函数 _VSTD::construct_at(__p, _VSTD::forward<_Args>(__args)...); ^~~~~~~~~~~~~~~~~~~ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:897:17: 注意:宏‘_VSTD’展开为‘std’ # define _VSTD std ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__tree:2144:20: 注意:实例化函数模板特化‘std::allocator_traits<std::allocator<std::__tree_node<std::__value_type<std::string, std::unique_ptr<Person>>, void *>>>::construct<std::pair<const std::string, std::unique_ptr<Person>>, const std::pair<const std::string, std::unique_ptr<Person>> &, void, void>’时请求 __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_), _VSTD::forward<_Args>(__args)...); ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__tree:2127:29: 注意:实例化函数模板特化‘std::__tree<std::__value_type<std::string, std::unique_ptr<Person>>, std::__map_value_compare<std::string, std::__value_type<std::string, std::unique_ptr<Person>>, std::less<std::string>>, std::allocator<std::__value_type<std::string, std::unique_ptr<Person>>>>::__construct_node<const std::pair<const std::string, std::unique_ptr<Person>> &>’时请求 __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...); ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__tree:1274:16: 注意:实例化函数模板特化‘std::__tree<std::__value_type<std::string, std::unique_ptr<Person>>, std::__map_value_compare<std::string, std::__value_type<std::string, std::unique_ptr<Person>>, std::less<std::string>>, std::allocator<std::__value_type<std::string, std::unique_ptr<Person>>>>::__emplace_hint_unique_key_args<std::string, const std::pair<const std::string, std::unique_ptr<Person>> &>’时请求 return __emplace_hint_unique_key_args(__p, _NodeTypes::__get_key(__v), __v).first; ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/map:1318:29: 注意:实例化成员函数‘std::__tree<std::__value_type<std::string, std::unique_ptr<Person>>, std::__map_value_compare<std::string, std::__value_type<std::string, std::unique_ptr<Person>>, std::less<std::string>>, std::allocator<std::__value_type<std::string, std::unique_ptr<Person>>>>::__insert_unique’时请求 {return __tree_.__insert_unique(__p.__i_, __v);} ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/map:1339:17: 注意:实例化成员函数‘std::map<std::string, std::unique_ptr<Person>>::insert’时请求 insert(__e.__i_, *__f); ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/map:1147:13: 注意:实例化函数模板特化‘std::map<std::string, std::unique_ptr<Person>>::insert<std::__map_const_iterator<std::__tree_const_iterator<std::__value_type<std::string, std::unique_ptr<Person>>, std::__tree_node<std::__value_type<std::string, std::unique_ptr<Person>>, void *> *, long>>>’时请求 insert(__m.begin(), __m.end()); ^ personal-record.cc:43:7: 注意:实例化成员函数‘std::map<std::string, std::unique_ptr<Person>>::map’时请求 class PersonContainer { ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/construct_at.h:39:38: 注意:候选模板被忽略:替换失败[with _Tp = std::pair<const std::string, std::unique_ptr<Person>>, _Args = <const std::pair<const std::string, std::unique_ptr<Person>> &>]:调用了被隐式删除的‘std::pair<const std::string, std::unique_ptr<Person>>’拷贝构造函数 _LIBCPP_HIDE_FROM_ABI constexpr _Tp* construct_at(_Tp* __location, _Args&&... __args) { ^ 生成1个错误。
内容的提问来源于stack exchange,提问作者meetanandkr
相关产品推荐
相关产品推荐

