如何正确实现具有原始指针的类的复制构造函数?



我在C++中有一个 objcet,我通过extern "c"作为指针导出。为了能够创建对象并返回它,鉴于尝试返回本地范围变量的范围问题,我必须在堆上执行此操作。但是,为了在堆上分配,我必须能够复制一个对象,这是我正在努力做到的。下面是一个示例:

#include <iostream>
using namespace std;
// used to simulate complex data structure in nex object
class DataStorage {
private:
int a;
public:
explicit DataStorage(int a) : a(a) {
}
};
// object for export "C". Contains some pointers. 
class NonTrivialObject {
public:
int *int_ptr;
char *char_ptr;
double *double_ptr;
DataStorage *data_storage_ptr;
NonTrivialObject(int *int_ptr, char *char_ptr, double *double_ptr, DataStorage *data_storage_ptr)
: int_ptr(int_ptr), char_ptr(char_ptr), double_ptr(double_ptr), data_storage_ptr(data_storage_ptr) {}
~NonTrivialObject() {
/*
* only delete objects of allocated on heap
*/
}
/*
* Copy constructor
*/
NonTrivialObject(const NonTrivialObject &rhs) {
if (this != &rhs) {
this->int_ptr = rhs.int_ptr;
this->char_ptr = rhs.char_ptr;
this->double_ptr = rhs.double_ptr;
this->data_storage_ptr = rhs.data_storage_ptr;
}
}
/*
* Copy assignment constructor
*/
NonTrivialObject &operator=(const NonTrivialObject &rhs) {
if (this != &rhs) {
this->int_ptr = rhs.int_ptr;
this->char_ptr = rhs.char_ptr;
this->double_ptr = rhs.double_ptr;
this->data_storage_ptr = rhs.data_storage_ptr;
}
return *this;
}
/*
* Move assignment constructor
*/
NonTrivialObject &operator=(NonTrivialObject &&rhs) noexcept {
if (this != &rhs) {
this->int_ptr = rhs.int_ptr;
this->char_ptr = rhs.char_ptr;
this->double_ptr = rhs.double_ptr;
this->data_storage_ptr = rhs.data_storage_ptr;
}
return *this;
}
/*
* Move constructor
*/
NonTrivialObject(NonTrivialObject &&rhs) noexcept {
if (this != &rhs) {
this->int_ptr = rhs.int_ptr;
this->char_ptr = rhs.char_ptr;
this->double_ptr = rhs.double_ptr;
this->data_storage_ptr = rhs.data_storage_ptr;
}
}
};
extern "C" {
// first method will not work because nonTrivialObjectPtr is locally scoped
NonTrivialObject *CopyANonTrivialObject1(NonTrivialObject obj) {
auto *nonTrivialObjectPtr = (NonTrivialObject *) malloc(sizeof(obj));
nonTrivialObjectPtr = &obj;
return nonTrivialObjectPtr;//Address of local variable may escape the function
}
// Only creates a local copy, presumably due to the contents of copy operator
NonTrivialObject *CopyANonTrivialObject2(NonTrivialObject obj) {
auto *nonTrivialObjectPtr = (NonTrivialObject *) malloc(sizeof(obj));
*nonTrivialObjectPtr = obj;
return nonTrivialObjectPtr;
}
}
int main() {
int i = 3;
char c = 's';
double dub = 3.98;
DataStorage dataStorage(4);
NonTrivialObject nonTrivialObject(&i, &c, &dub, &dataStorage);
NonTrivialObject* nonTrivialObject2 = CopyANonTrivialObject2(nonTrivialObject);
cout << nonTrivialObject.int_ptr << ", " << *nonTrivialObject.int_ptr << endl;
cout << nonTrivialObject2->int_ptr << ", " << *nonTrivialObject2->int_ptr << endl;
free(nonTrivialObject2);
return 0;
};

将输出

0x7ffd59c4ac28, 3
0x7ffd59c4ac28, 3

指示副本是浅层副本。我知道

/*
* Copy constructor
*/
NonTrivialObject(const NonTrivialObject &rhs) {
if (this != &rhs) {
this->int_ptr = rhs.int_ptr;
this->char_ptr = rhs.char_ptr;
this->double_ptr = rhs.double_ptr;
this->data_storage_ptr = rhs.data_storage_ptr;
}
}

是问题所在,但在修复它的过程中,我不断遇到分段错误。我尝试了各种形式的取消引用和获取内存地址,并尝试用memcpystd::copy替换赋值,这两者都在valgrind中非常不受欢迎。

如何将此类修改为完全可复制,以便保存数据的内存位置不同但值相同?

如何正确实现具有原始指针的类的复制构造函数?

这要看情况。

类是否拥有指向的对象?如果不涉及所有权,并且类仅指向其生存期未绑定到类的对象,则只需复制指针即可。请注意,由于在这种情况下,类无法控制指向对象的生存期,因此必须非常小心地确保指向对象的生存期比指向它的类实例长。这称为浅拷贝。

如果类确实拥有该对象,因此对其生存期负责,则首先不要使用原始指针。请改用智能指针或容器。但是,如果要使用原始指针(但不要使用(,则可以动态分配指向对象的副本。这称为深层复制。


不要在C++中使用malloc和free。

最新更新