如何正确实现具有原始指针的 class 的复制构造函数?
How to properly implement a copy constructor of a class that has raw pointers?
我有一个 C++ 对象,我通过 extern "c"
作为指针导出。为了能够创建对象并 return 它,我必须在堆上进行,考虑到尝试 return 局部范围变量的范围问题。但是,为了在堆上分配,我必须能够复制一个对象,我正在努力做到这一点。这是一个例子:
#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;
}
}
是问题所在,但为了修复它,我不断遇到分段错误。我尝试了各种形式的取消引用和获取内存地址,并尝试用 memcpy
和 std::copy
替换赋值,这两种方法在 valgrind 中都很不受欢迎。
我如何修改此 class 使其完全可复制,以便保存数据的内存位置不同但值相同?
How to properly implement a copy constructor of a class that has raw pointers?
视情况而定。
class是否拥有尖头物体?如果不涉及所有权,并且 class 仅指向其生命周期未绑定到 class 的对象,则只需复制指针即可。请注意,由于 class 在这种情况下无法控制指向对象的生命周期,因此您必须非常小心以确保指向对象的生命周期比指向的 class 实例更长它。这称为浅拷贝。
如果 class 确实拥有对象并因此对其生命周期负责,那么首先不要使用原始指针。相反,使用智能指针或容器。但是如果你要使用原始指针(但没有),那么你将动态分配指向对象的副本。这称为深拷贝。
不要在 C++ 中使用 malloc 和 free。
我有一个 C++ 对象,我通过 extern "c"
作为指针导出。为了能够创建对象并 return 它,我必须在堆上进行,考虑到尝试 return 局部范围变量的范围问题。但是,为了在堆上分配,我必须能够复制一个对象,我正在努力做到这一点。这是一个例子:
#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;
}
}
是问题所在,但为了修复它,我不断遇到分段错误。我尝试了各种形式的取消引用和获取内存地址,并尝试用 memcpy
和 std::copy
替换赋值,这两种方法在 valgrind 中都很不受欢迎。
我如何修改此 class 使其完全可复制,以便保存数据的内存位置不同但值相同?
How to properly implement a copy constructor of a class that has raw pointers?
视情况而定。
class是否拥有尖头物体?如果不涉及所有权,并且 class 仅指向其生命周期未绑定到 class 的对象,则只需复制指针即可。请注意,由于 class 在这种情况下无法控制指向对象的生命周期,因此您必须非常小心以确保指向对象的生命周期比指向的 class 实例更长它。这称为浅拷贝。
如果 class 确实拥有对象并因此对其生命周期负责,那么首先不要使用原始指针。相反,使用智能指针或容器。但是如果你要使用原始指针(但没有),那么你将动态分配指向对象的副本。这称为深拷贝。
不要在 C++ 中使用 malloc 和 free。