教育程序,用于通过值将参数传递给构造方法和设置方法(现代C ++,示例)

从下一篇文章中的评论habr.com/en/post/460831/#comment_20416435以及在那里进行的讨论来看,关于如何正确地将参数传递给构造函数或setter的文章不会妨碍Habré。 StackOverflow有很多类似的资料,但是我不记得这里的内容。

因为该文章中的示例是完全正确的,并且该文章的作者是绝对正确的。 这是一个例子:

// . struct person { person(std::string first_name, std::string last_name) : first_name{std::move(first_name)} //  , last_name{std::move(last_name)} // std::move  ! {} private: std::string first_name; std::string last_name; }; 

此类代码使您可以涵盖使用该类的所有(几乎所有)可能的选项:

 std::string first{"abc"}, last{"def"}; person p1{first, last}; // (1)    person p2{std::move(first), last}; // !!!    person p2{std::move(first), std::move(last)}; // (3)   person p3{"x", "y"}; //   

与旧方法比较,当由const&:传递时,肯定更糟,因为它不包括选项(3):

 // . struct person { person(const std::string& first_name, const std::string& last_name) : first_name{first_name} , last_name{last_name} {} private: std::string first_name; std::string last_name; }; std::string first{"abc"}, last{"def"}; person p1{first, last}; //  ,    //      ,  first  last    // ?         //   0 !  const& . 

使用&&的替代方法也更糟,但方向相反:

 // . struct person { person(std::string&& first_name, std::string&& last_name) : first_name{std::move(first_name)} , last_name{std::move(last_name)} {} private: std::string first_name; std::string last_name; }; std::string first{"abc"}, last{"def"}; person p1{std::move(first), std::move(last)}; //  //       ,    &&  : person p2{std::string{first}, std::string{last}}; // FOOOO 

如果您不害怕组合爆炸,可以给&&一个机会(但是为什么呢?速度没有真正的提高,优化器也不会停止工作):

 //   . struct person { person(std::string&& first_name, std::string&& last_name) : first_name{std::move(first_name)} , last_name{std::move(last_name)} {} person(const std::string& first_name, std::string&& last_name) : first_name{first_name} , last_name{std::move(last_name)} {} person(std::string&& first_name, const std::string& last_name) : first_name{std::move(first_name)} , last_name{last_name} {} person(const std::string& first_name, const std::string& last_name) : first_name{first_name} , last_name{last_name} {} private: std::string first_name; std::string last_name; }; 

或同一件事,仅使用模板(但又为什么?):

 //     (   ),      . struct person { template <typename T1, typename T2> person(T1&& first_name, T2&& last_name) : first_name{std::forward<T1>(first_name)} , last_name{std::forward<T2>(last_name)} {} private: std::string first_name; std::string last_name; }; 

即使您没有std :: string,而是您自己编写的大型类的某个对象,并且希望人们移动它(而不是复制),那么在这种情况下,最好禁止构造函数从该大型类中进行复制,而不是将其传递给任何地方由&&。 这样更可靠,代码更短。

最后,关于如何做不到的几个选择:

 // . struct person { person(const std::string& first_name, const std::string& last_name) : first_name{first_name} , last_name{last_name} {} private: //   :  ,     //     const std::string& first_name; const std::string& last_name; }; person p{"x", "y"}; // --,  

所以不要:

 // . struct person { person(std::string& first_name, std::string& last_name) : first_name{first_name} , last_name{last_name} {} private: //   ,      shared_ptr: //  ,   std::string& first_name; std::string& last_name; }; 

为什么会这样,基本原理是什么? 这很简单:通常,对象应拥有其属性。

如果对象不想拥有某物,则它可以为此“物”拥有shared_ptr。 顺便说一句,在这种情况下,shared_ptrs也必须通过值传递,而不是通过常量链接传递-与本文开头的第一个示例没有区别:

 //  (  ). struct person { person(std::shared_ptr<portfolio> pf) : pf{std::move(pf)} // std::move     {} private: std::shared_ptr<portfolio> pf; }; auto psh = std::make_shared<portfolio>("xxx", "yyy", "zzz"); ... person p1{psh}; person p2{std::move(psh)}; // (X)  ,  psh    

请注意:std ::移动shared_ptr是完全合法的,它消除了将shared_ptr链接计数器锁定在内存中的开销(数百个CPU周期)及其增量。 它不会影响对象及其链接的寿命。 但是,当然,只有不再需要下面代码中的psh链接时,才可以执行(X)。

道德:一般不要使用const&。 根据情况看。

聚苯乙烯
传递构造函数参数时,请使用{}代替()。 时尚,现代,青春。

PPS
总之,还有一件事:std :: move()实际上不移动任何东西,它本身转换为零汇编程序指令。 std :: move()所做的全部工作就是在链接上放置一个特殊的“粘性标签”,将其转换为&&-rvalue引用。 此外,使用此标签,您可以单独“匹配”函数参数的类型(例如,对于&&-参数有单独的函数重载,对于&-parameter有单独的函数重载)。 &&-标签的含义是使调用代码能够告诉被调用者:“如果需要,您可以从此链接中获取值,我不再需要它; 但是只有当你吃饭时,才留下骨头,然后我仍然需要为剩下的骨骼调用析构函数。” 取得同样的成功,就有可能传输普通的&链接(您也可以使用它们“吃掉”一个对象),但是使用&&语义更好,因为 您不会混淆:您可以在哪里吃饭,哪里只能闻到气味。

在这方面,应该将名称std :: move()识别为极其不成功。 将其命名为std :: eat_me_if_you_want()或std :: bon_appetit()是正确的。 但是std :: move()较短。

Source: https://habr.com/ru/post/zh-CN460955/


All Articles