如何在构造函数初始化阶段完成vector中智能指针对象的克隆并创建std::set容器?
解决方案:在初始化阶段完成std::set的构造
当然可以做到!你想要把克隆和std::set的构造逻辑都放到初始化阶段、摆脱构造函数里的循环,其实可以借助C标准库的迭代器和初始化列表特性来实现,下面两种方案分别适配不同的C版本:
方案一:C++11及以上兼容版本
我们可以用**lambda表达式配合std::transform**在成员初始化列表里生成一个临时的、包含克隆后指针的容器,直接用它来构造std::set。这样所有逻辑都在初始化阶段完成,构造函数体内完全不需要循环:
#include <memory> #include <set> #include <vector> #include <algorithm> // 用于std::transform class A { public: typedef A self; A() = default; A(const self& another) = default; virtual ~A() = default; std::unique_ptr<A> clone() const { return std::make_unique<A>(); } }; class SetOfA { public: SetOfA() = default; // 优化后的构造函数:逻辑全部在初始化列表中 SetOfA(const std::vector<std::unique_ptr<A>>& data) : set_of_a([&]() { // 在lambda里完成克隆元素的生成 std::vector<std::unique_ptr<A>> cloned_elements; cloned_elements.reserve(data.size()); // 预分配空间提升性能 std::transform( data.begin(), data.end(), std::back_inserter(cloned_elements), [](const std::unique_ptr<A>& ptr) { return ptr->clone(); // 调用克隆方法生成新指针 } ); return cloned_elements; }()) // 执行lambda,返回的临时vector用来构造set {} private: std::set<std::unique_ptr<A>> set_of_a; };
这里的核心是:lambda表达式会在初始化set_of_a时执行,生成一个包含所有克隆后指针的临时std::vector,然后std::set会直接用这个vector的迭代器完成构造,全程不需要在构造函数体内写循环。
方案二:C++20及以上更简洁版本
如果你可以使用C++20的范围库(Ranges),可以直接用std::ranges::transform_view来生成一个“视图”,不需要临时vector,直接把转换后的元素序列传给std::set的构造函数,代码会更简洁:
#include <memory> #include <set> #include <vector> #include <ranges> // C++20范围库 class A { public: typedef A self; A() = default; A(const self& another) = default; virtual ~A() = default; std::unique_ptr<A> clone() const { return std::make_unique<A>(); } }; class SetOfA { public: SetOfA() = default; // C++20优化版本:直接用transform_view构造set SetOfA(const std::vector<std::unique_ptr<A>>& data) : set_of_a( std::ranges::transform_view( data, [](const std::unique_ptr<A>& ptr) { return ptr->clone(); } ) ) {} private: std::set<std::unique_ptr<A>> set_of_a; };
std::ranges::transform_view相当于一个“懒加载”的转换层,它不会提前生成所有克隆元素,而是在std::set构造时按需生成并插入,既避免了临时容器的开销,又完全满足你在初始化阶段完成逻辑的需求。
补充说明
- 两种方案都利用了
std::set的范围构造函数,该函数可以接受任意输入迭代器序列来初始化集合。 std::unique_ptr是不可复制的,但clone()返回的是右值(临时对象),可以被正确移动到std::set中,没有所有权问题。
内容的提问来源于stack exchange,提问作者one_two_three
相关产品推荐
相关产品推荐

