【问题标题】:How to Create Object Copy如何创建对象副本
【发布时间】:2017-03-30 14:53:01
【问题描述】:

现在我正在跨两个 .cpp 文件处理两个函数。假设我正在使用一个名为 someStruct 的结构:

struct someStruct {
  int num;
}

A.cpp:

int main() {
  someStruct *a = NULL;
  bool ret;
  ret = foo(a);
  std::cout << a->num; // should print 5
}

B.cpp:

bool foo(someStruct *a) {
  someStruct *b = someFunction(); // points to an instance of someStruct on the stack
  // note that b->num should hold 5

  // need something here
  // ATTEMPT 1:
  a = new someStruct(*b);
  // ATTEMPT 2
  a = (someStruct *)malloc(sizeof(someStruct));
  a = memcpy(a, b, sizeof(someStruct));
}

我想要完成的是让主函数中的a 最终指向someStruct 的实例,该实例与foo() 中的结构指针b 具有相同的值。

我列出的尝试都没有奏效。

【问题讨论】:

  • Find a good beginners book 并阅读references。或者,不要在main 函数中声明指向someStruct 的指针,并在将a 传递给foo 时使用地址运算符,然后在foo 中使用解引用和赋值(如@ 987654335@).
  • someStruct *b = someFunction(); // points to an instance of someStruct on the stack - 这听起来像是即将导致未定义的行为(如果你的函数在本地分配了struct,它的生命周期在函数返回时结束)
  • 不要在 C++ 中使用malloc
  • foo(a); 不会改变main()a 的值,它是一个空指针。 a-&gt;num 尝试取消引用空指针。如果不更改 foo() 签名,更改其正文将无济于事。
  • 只复制整个对象,不用担心动态分配和指针。

标签: c++


【解决方案1】:

术语:堆与堆栈

您的问题应该命名为“如何创建对象副本”。一个原因是原始对象位置无关紧要,从堆栈上的对象和堆上的对象创建副本几乎相同。第二个原因是您当前的代码尝试复制由someFunction() 返回值指向的对象,这可能只有在someFucntion() 在堆上创建对象时才有意义。否则,如果 someFunction() 在堆栈上创建对象,如下所示:

someStruct tmp;
tmp.num = 5; 
return &tmp;

然后一旦someFunction() 完成执行,它的堆栈帧就会被释放,并且可能会被其他函数堆栈重用。因此 'tmp' 结构位于内存中,它可以随时被覆盖,所以你不能依赖它的数据。局部变量超出范围后,切勿使用指向局部变量的指针。

复制对象

嗯,你的 ATTEMPT 1 没问题。使用new 创建类或结构调用构造函数来构建对象。您传递了另一个对象作为参数,因此调用了复制构造函数。您没有编写复制构造函数,但编译器自动创建了一个微不足道的构造函数,因此它正确地将所有字段从原始对象复制到新创建的对象。

但是,cout 没有显示预期的输出,因为程序的另一部分存在错误。调用foo(a); 意味着将a 的副本作为参数传递给foo。因此,您不会在foo 内更改maina 值,而是更改fooa 副本的值。返回 main 时,a 仍然是 NULL 并且不能被取消引用。作为最小的修复,您需要通过指针或引用传递a(它已经是指针,所以有点混乱)而不是通过值传递它。示例:

int main() {
  someStruct *a = NULL;
  bool ret;
  ret = foo(&a);
  std::cout << a->num; // should print 5
  delete a;
  return ret;
}

bool foo(someStruct **x) {
  someStruct *b = someFunction(); // points to an instance of someStruct on the heap
  *x = new someStruct(*b);
  delete b;
  return true;
};

养成为每个动态分配的缓冲区最终调用delete 的好习惯,对于较大的程序,内存泄漏可能会变得相当痛苦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-08
    • 2020-03-03
    • 2011-06-15
    • 2010-09-16
    相关资源
    最近更新 更多