将大量内存传递给类的构造函数的正确方法是什么?

What is the proper way to pass a large amount of memory to a constructor for a class?

提问人:EmbeddedDOOD 提问时间:8/26/2022 更新时间:8/26/2022 访问量:154

问:

对于此示例,请考虑这两个类。

第一个类定义一个具有单个公共成员的简单类。

class Tester
{
public:
    int m_tester_value;    

    Tester(){}

    Tester(int test_val)
    {
      m_tester_value = test_val;
    } 
    
    Tester(const Tester & data) : m_tester_value(data.m_tester_value)
    {
      std::cout << "Tester Copied!" << std::endl;
    }

    Tester& operator=(const Tester & data)
    {        
       m_tester_value = data.m_tester_value;

      return *this;
    }
};

第二个类还定义了一个具有单个公共成员的简单类,但此成员是第一个类中的对象向量。Tester

class VectorTester
{
  public:
    std::vector<Tester> m_vector;

  VectorTester(std::vector<Tester>* vector_construct)
  {
    if(vector_construct != nullptr)
    {
      m_vector = *vector_construct;
    }
  }

  VectorTester(const VectorTester & data) :       
                m_vector(data.m_vector)
  {
    std::cout << "VectorTester Copied!" << std::endl;
  }
      
};

我相信我正在尝试在类中复制向量。VectorTester

我编写了一个简单的函数,它将为我生成一个。vector<Tester>

std::vector<Tester> TesterVectorGenerator(void)
{
  std::vector<Tester> ret_vector;
  ret_vector.reserve(2);

  ret_vector.emplace_back(65);
  ret_vector.emplace_back(75);

  return ret_vector;
}

为了测试此代码,我使用了此示例。

int main() {
  std::vector<Tester> my_test_vector = TesterVectorGenerator();

  VectorTester vector_test = VectorTester(&my_test_vector);
    
  for (const auto &i : vector_test.m_vector)
  {
     // access by value, the type of i is int
     std::cout << "VectorTester.m_vector:" << i.m_tester_value << std::endl;
  }

  for (const auto &i : my_test_vector)
  {
     // access by value, the type of i is int
     std::cout << "my_test_vector:" << i.m_tester_value << std::endl;
  }  
}

一切似乎都按预期工作,输出如下所示:

Tester Copied!
Tester Copied!
VectorTester.m_vector:65
VectorTester.m_vector:75
my_test_vector:65
my_test_vector:75

问题 1:这是将大量数据传递到类中的最佳方式吗?由于指针只有 4 个字节的内存,我认为这比将整个值传递到类中并以这种方式复制它要好。

问题 2:对于这种为 C++ 传递数据的做法,是否有任何标准的习语?

感谢您对问题和手头代码的任何回复和输入。我对C++比较陌生,我很感激任何帮助!

C++ 对象 指针 参数传递

评论

2赞 George 8/26/2022
我不确定我是否理解这个问题,使用这两个构造函数,您都在复制向量。只要这是你的意图,这并没有错。C++ 也有移动的概念,这将比复制向量便宜,但会使源向量(正在移动的向量)不可用。
0赞 EmbeddedDOOD 8/26/2022
其中一个构造函数是复制构造函数,另一个是类的普通构造函数。我很好奇是否有更好的方法来传递大量数据。例如,假设它不是一个向量,而是一个大对象,我需要它作为我的类的成员。我应该如何将这些信息传递给我的班级?
0赞 user4581301 8/26/2022
归根结底是同一件事:源是可移动的和可消耗的吗?如果类必须保存 X 的副本,则必须复制或移动该 X。也许你可以让省略为你工作,但如果源可能为空,那就不行了。
0赞 yano 8/26/2022
这完全取决于您的类是否需要自己的数据集副本。如果是这样,那么就没有办法复制它了。如果没有,您可以传入指向它的指针或引用,了解如果引用的对象消失,就会发生不好的事情。也可以如前所述移动它,了解对源的影响。
0赞 EmbeddedDOOD 8/26/2022
在这种情况下,我希望确保即使传入的变量不再存在于内存中,类中的实例也存在。因此,我认为副本是必要的。那么,这是否被认为是复制数据的最佳实践呢?

答:

1赞 oraqlle 8/26/2022 #1

第1项质询

复制构造函数与准婚指针构造函数(即)一样有效,但更安全,因为引用不能是 .编译后,引用可能只是指向编译器的指针(参见:[https://www.godbolt.org/z/qsWdr4qTc])。因此,如果您希望将所有资源从一个对象/类型/类复制到另一个对象/类型/类,请使用复制构造函数,因为它比指针版本更安全且速度更快。至于对象资源复制的效率,这取决于你如何进行复制。在你的例子中,使用 std::vectors 复制构造函数(就像你已经拥有的一样)可能是最有效的。VectorTester(std::vector<Tester>* vector_construct)nullptr

第2项质询

在 C++ 中,有几种类型的构造函数,最著名的是默认构造函数、复制构造函数和移动构造函数。有一些特定的语义用于指定哪个构造函数是哪个构造函数。

  1. 默认 - 将对象及其资源初始化为默认状态。
  2. 复制 - 复制其他对象的状态,并将数据从其资源复制到新对象。
  3. 移动 - 克隆其他对象的状态,并将其资源的所有权移动到新对象,使另一个对象处于默认状态的未指定状态。
  4. 参数化构造函数 - 使用显式参数来初始化对象(例如,用于为数据结构类型保留内存的大小构造函数)。
  5. Initializer List 构造函数 - 用于初始化对象。std::initializer_list

下面是一个示例类,其中实现了前三个构造函数签名,这些签名与您的问题最相关。

class A
{
private:
    int i;

public:

    /// Default Constructor
    A()
    : i(0) {};

    /// Copy Constructor
    A(const A& a)
    : i(a.i) {};

    /// Move Constructor
    A(A&& a)
    : i(a.i)
    { a.i = 0; };  ///< Leaves `a` in default state
};

上面示例中的签名是 C++ 中指定默认、复制和移动构造函数的最惯用方式 C++.在这里看到它的实际效果。