繁体   English   中英

C++:将 object 传递给 class 构造函数,它是如何存储的?

[英]C++: Passing object to class constructor, how is it stored?

考虑以下在 C++ 中实现的简单 class 示例。

foo.hpp

#include <vector>
class Foo {
private:
    std::vector<double> X;
public:
    Foo() = default;
    ~Foo() = default;
    Foo(std::vector<double>&);
};

foo.cpp

#include "Foo.hpp"
Foo::Foo(std::vector<double>& X):
        X(X)
{}

在这种情况下,向量 X 通过引用传递给 class Foo 的构造函数。 不过,我开始怀疑实现中的操作 X(X) 是否会复制并将其“粘贴”到 class 的成员 X 中。

它是哪一个?

是的,数据成员X将从构造函数参数X复制初始化。

如果将数据成员X声明为引用,则不会发生复制操作。 例如

class Foo {
private:
    std::vector<double>& X;
public:
    ~Foo() = default;
    Foo(std::vector<double>&);
};

Foo::Foo(std::vector<double>& X):
        X(X)
{}

然后

std::vector<double> v;
Foo f(v); // no copies; f.X refers to v

Rest 放心。 该成员的类型是vector<double> ,因此编译器将在vector<double> class 中查找与提供的参数类型( vector<double>& )匹配的构造函数重载。

它会找到的最佳匹配是const vector<double>&重载 - 复制构造函数。

作为替代方案,您可以为 class 创建一个带有右值引用的构造函数:

#include <vector>
class Foo {
private:
    std::vector<double> X;
public:
    Foo() = default;
    ~Foo() = default;
    Foo(const std::vector<double>&);
    Foo(std::vector<double>&&);
};

然后构造函数将像这样实现:

Foo::Foo(std::vector<double>&& X_) : X(std::move(X_)) {}

调用此构造函数时不进行任何复制。

在您的示例中, X ( Foo 类的成员)是copy-constructed 防止复制的一种解决方案是将 X 定义为 Foo class 中的lvalue reference ,尽管它不是适用于所有情况的通用解决方案,并且如果原始 X 的 scope 为当 Foo 还活着时完成,总而言之,根据您的应用程序,您有以下选项之一

  1. 使用对 X 的lvalue reference ,如果每个可能的 Foo object 的 scope 低于传递的 object (X):

    foo.hpp

     #include <vector> class Foo { private: std::vector<double> &X; public: Foo() = default; ~Foo() = default; Foo(std::vector<double>&); };

    foo.cpp

     #include "Foo.hpp" Foo::Foo(std::vector<double>& X): X(X) // keep the lvalue refrence to the passed Object {}

然后

std::vector<double> v;
Foo f(v); // no copies; f.X refers to v
// Foo function calls including f.X should be finished before destruction of the v Object
  1. 将 X 转换为rvalue reference (std::move) 并将其移动到 Foo class 的成员 X,如果在 Foo 构造函数调用之后通过传递的 Object 名称不应该使用 X 内容:

    foo.hpp

     #include <vector> class Foo { private: std::vector<double> X; public: Foo() = default; ~Foo() = default; Foo(std::vector<double>&&); };

    foo.cpp

     #include "Foo.hpp" Foo::Foo(std::vector<double>&& X): X(X) // move constructor of std::vector<double> is called in this line {}

然后

std::vector<double> v = {1.0, 2.0, 3.0}; 
Foo f(std::move(v)); // no copies; f.X use resource of v, but v is empty now
// v is empty now
  1. 最后一种方法与您的实现完全相同。 在这种情况下: foo.hpp

     #include <vector> class Foo { private: std::vector<double> X; public: Foo() = default; ~Foo() = default; Foo(const std::vector<double>&); };

    foo.cpp

     #include "Foo.hpp" Foo::Foo(const std::vector<double>& X): // using const is better: in this case X(X) // copy constructor of std::vector<double> is called in this line {}

然后

std::vector<double> v = {1.0, 2.0, 3.0};
Foo f(v); // do copies; f.X copy the resource of v, and v is still valid

话虽如此,根据情况,所有这些方法都有自己的应用程序。 为了清楚起见,只需简单地应用此优先级规则:
1-通过rvalue reference传递,这导致成员的move constructor (例如,当您想将 object 传递给 std::thread 构造函数时,以及所有权,即资源,以及资源生命周期。)。
2-传递lvalue reference并保留它,当传递的 object 生命周期(在这些示例中为 v)大于引用的生命周期时。
3- 传递const lvalue reference并调用copy constructor copy constructor在这些示例中为std::vector的复制构造函数),当最后的选择不适用时,或者由于进一步使用传递的lifetime或由于通过 Object。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM