类转换直接初始化消除中间对象的规则?与工厂函数、Wrapper的差异
关于std::tuple与自定义Wrapper中对象初始化优化的疑问
背景
我在寻找std::tuple原地初始化的方法时,发现了一个依赖类间转换的已发布解决方案。为了理解是什么规则导致中间对象被消除,我构建了以下最小示例:
#include <cstdio> #include <tuple> class To { public: To() { std::puts("default constructor"); } explicit To(int input) : val(input) { std::puts("value constructor"); } // noexcept is a sweet lie because of std::puts To(To&& object) noexcept : val(object.val) { std::puts("move constructor"); } // noexcept is a sweet lie because of std::puts To& operator=(To&& object) noexcept { val = object.val; std::puts("move assign"); return *this; } ~To() noexcept { std::puts("destructor"); } private: int val = -1; }; class From { public: explicit From(int input) : val(input) { std::puts("From value constructor"); } // marking explicit to inhibit to1 assignement operator To() const&& { return To{val}; }; private: int val = -1; }; To Make_To(int val) { return To{val}; } int main() { std::puts("-----------------"); std::puts("# direct init with conversion"); const std::tuple<To> tp0{From{0}}; std::puts("# direct init with creator"); const std::tuple<To> tp1{Make_To(1)}; std::puts("# init and assign"); std::tuple<To> tp2; tp2 = From{2}; std::puts("# finish"); }
使用C++17编译后,输出结果如下:
----------------- # direct init with conversion From value constructor value constructor # direct init with creator value constructor move constructor destructor # init and assign default constructor From value constructor value constructor move assign destructor # finish destructor destructor destructor
我将创建并赋值的情况作为RVO无法完全生效的参考场景(因为目标对象已开始生命周期)。想了解为什么类转换初始化与工厂函数初始化之间存在差异?
扩展示例
将std::tuple替换为简单的Wrapper后,代码如下:
struct Wrapper { Wrapper(To&& Input) : val(Input) { std::puts("Wrapper To&& constructor"); }; Wrapper(const To& Input) : val(Input) { std::puts("Wrapper const To& constructor"); }; private: To val; }; int main() { std::puts("-----------------"); std::puts("# Wrapper direct init with conversion"); const Wrapper d0(From{0}); std::puts("# Wrapper direct init with creator"); const Wrapper d1(Make_To(1)); std::puts("-----------------"); std::puts("# finish"); }
编译后输出结果:
----------------- # Wrapper direct init with conversion From value constructor value constructor copy constructor Wrapper from To&& constructor destructor # Wrapper direct init with creator value constructor copy constructor Wrapper from To&& constructor destructor ----------------- # finish destructor destructor
这与std::tuple版本的输出差异很大,而我原本预期结果一致,这是为什么?
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

