gpt4 book ai didi

c++ - 将参数传递给构造函数和成员函数时 move 或复制

转载 作者:行者123 更新时间:2023-11-28 04:37:13 24 4
gpt4 key购买 nike

以下是我的典型代码示例。 A 有很多看起来像这样的对象:

struct Config
{
Config();
Config(const std::string& cType, const std::string& nType); //additional variables omitted
Config(Config&&) = default;
Config& operator=(Config&&) = default;

bool operator==(const Config& c) const;
bool operator!=(const Config& c) const;

void doSomething(const std::string& str);
bool doAnotherThing(const MyOtherObject& obj);
void doYetAnotherThing(int value1, unsigned long value2, const std::string& value3, MyEnums::Seasons value4, const std::vector<MySecondObject>& value5);

std::string m_controllerType;
std::string m_networkType;
//...
};

//...

Config::Config(const std::string& cType, const std::string& nType) :
m_controllerType(cType),
m_networkType(nType)
{
}

我的动机和对该主题的一般理解:

  • 在构造函数和方法中使用 const 引用以避免在传递对象时进行双重复制。
  • 简单类型——按值传递;类和结构 - 通过 const 引用传递(或当我需要修改它们时的简单引用)
  • 强制编译器创建default move 构造函数和 move 赋值,这样它就可以发挥神奇的作用,同时可以避免编写无聊的 ctor() : m_v1(std::move(v1)), m_v2(std::move(v2)), m_v3(std::move(v3)) {} .
  • 如果表现不好,使用 libc 和原始指针,然后在类里面包装它并写评论。

我有一种强烈的感觉,根据经验法则是有缺陷的,而且根本不正确。

在阅读了 cppreference、Scott Mayers、C++ standard、Stroustrup 等之后,我觉得:“是的,我理解这里的每一个词,但它仍然没有任何意义”。我唯一理解的是当我的类包含不可复制的类型(如 std::mutexstd::unique_ptr )时, move 语义才有意义。

我见过很多代码,人们在其中按值传递复杂对象,例如大字符串、 vector 和自定义类 - 我相信这是 move 语义发生的地方,但是,同样,如何将对象传递给函数通过 move ?如果我是正确的,它会使对象处于“某种空状态”,使其无法使用。

所以,问题是:- 我如何正确地决定按值传递和按引用传递?- 我需要同时提供复制和 move 构造函数吗?- 我是否需要显式编写 move 和复制构造函数?我可以使用 = default ?我的类(class)主要是 POD 对象,因此不涉及复杂的登录。-调试时,我总是可以写std::cout << "move\n";std::cout << "copy\n";在我自己的类的构造函数中,但我怎么知道来自 stdlib 的类会发生什么? ?

附言它可能看起来像是绝望的呼喊(确实如此),而不是一个有效的 SO 问题。我根本不知道如何更好地表述我的问题。

最佳答案

  • 如果是原始类型,按值传递。引用位置获胜。

  • 如果您不打算存储它的拷贝,请按值或 const& 传递。

  • 如果您想存储它的一个拷贝,而且 move 成本很低,复制成本适中,请按传递。

  • 如果某物的 move 成本适中,并且是接收器参数,请考虑通过右值引用传递。用户将被迫 std::move

  • 考虑为调用者提供一种方法,以将构造放入高度通用代码的字段中,或者您需要每一盎司性能的地方

The Rule of 0/3/5描述了你应该如何处理复制分配/构造/销毁。理想情况下,您遵循 0 的规则; copy/move/destruct 都是 =default 除了资源管理类型。如果你想实现复制/move/破坏的任何,你需要实现,=default or =delete 5 .

如果您只将 1 个参数传递给 setter,请考虑同时编写 &&const& 版本的 setter。或者只是暴露底层对象。 move 分配有时会重用存储,这很有效。

放置看起来像这样:

struct emplace_tag {};
struct wrap_foo {
template<class...Ts>
wrap_foo(emplace_tag, Ts&&...ts):
foo( std::forward<Ts>(ts)... )
{}
template<class T0, class...Ts>
wrap_foo(emplace_tag, std::initializer_list<T0> il, Ts&&...ts):
foo( il, std::forward<Ts>(ts)... )
{}
private:
Foo foo;
};

还有许多其他方法可以允许“放置”构造。也请参阅标准容器中的 emplace_backemplace(它们使用放置 ::new 构造对象,转发传入的对象)。

Emplace 构造甚至允许直接构造,甚至无需使用正确设置了 operator T() 的对象进行 move 。但这超出了这个问题的范围。

关于c++ - 将参数传递给构造函数和成员函数时 move 或复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51064862/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com