C++ return 按值 - 里面的指针会发生什么?
C++ return by value - what happens with the pointer inside?
所以我遇到了一些段错误,想知道是否有人可以更深入地向我解释这是如何工作的。
我有一个围绕数字变量的包装器 class,我正在尝试构建表达式的计算树。这是一个示例代码:
class DoubleWrap{
public:
static int id;
DoubleWrap(double value){this->value = value;myid=++id;}
double value;
int myid;
std::vector<DoubleWrap*> parents;
DoubleWrap operator+(DoubleWrap& x){
DoubleWrap result(this->value + x.value);
setParents(*this,result);
setParents(x,result);
return result;
}
void setParents(DoubleWrap& parent,DoubleWrap& child){
child.parents.push_back(&parent);
}
void printTree(){
std::cout<< "[" << this->myid << "]-(";
for (auto& elem: this->parents)
std::cout<< elem->myid << "," << elem <<",";
std::cout<<")"<<std::endl;
for (auto& elem: this->parents)
elem->printTree();
}
}
我遇到的问题是像 x = a+b+c+d 这样的表达式;当我尝试寻找 x 的 parents 时,它有 2 个 parents,但 parents[0].parents[0] 为零,例如由于某种原因,指向分配位置的指针不起作用或分配的内存被破坏?
如果有人可以就解决方法以及为什么会发生这种情况向我提供建议,我将非常感兴趣。
举个关于这段代码的例子:
DoubleWrap dw(12.6);
DoubleWrap dw2(12.5);
DoubleWrap dw3(12.4);
DoubleWrap dw4(12.3);
DoubleWrap a = dw + dw2 + dw3;
DoubleWrap b = a + dw+ dw2+ dw3 + dw4;
b.printTree();
我期望输出:
[10]-(9,0x13a4b50,4,0x7fff5bdb62f0,)
[9]-(8,0x13a4b00,3,0x7fff5bdb62c0,)
[8]-(7,0x13a49f0,2,0x7fff5bdb6290,)
[7]-(6,0x7fff5bdb6320,1,0x7fff5bdb6260,)
[6]-(5,0x13a4db0,3,0x7fff5bdb62c0,)
[5]-(1,0x7fff5bdb6260,2,0x7fff5bdb6290,)
[1]-()
[2]-()
[3]-()
[1]-()
[2]-()
[3]-()
[4]-()
但我得到的结果(通常在不同的运行中不同):
[10]-(9,0x7ffffd5e2f00,4,0x7ffffd5e2de0,)
[9]-(33,0x1c6da10,3,0x7ffffd5e2db0,)
Process finished with exit code 139
我的猜测是运算符的 return 实际上复制了 DoubleWrap 变量,因此 parents 中的指针指向的值超出范围并释放内存?
临时解决方案是return参考,但问题是为什么以及是否有合适的解决方案?
PS: 修复了之前我得到的一个错误,是 setParents 的错误。
您的代码:
DoubleWrap 运算符+(DoubleWrap& x){
DoubleWrap result(this->value + x->value);
如果 x 是指向 DoubleWrap class 的指针,那将是正确的,但是您已将 x 编码为 DoubleWrap class 对象而不是指针,因此您的代码
应该读 :
DoubleWrap 运算符+(DoubleWrap& x){
DoubleWrap result(this->value + x.value);
您的问题是您要将指向 临时对象 的指针添加到向量中。
DoubleWrap a = dw + dw2 + dw3;
以上会先调用dw.operator+(dw2)
。这会创建一个临时对象,我们将其命名为 temp
。然后调用 temp.operator+(dw3)
。现在在 operator+
中有一个对 setParents
的调用,您将 temp
作为 parent
传递。然后获取 temp
的地址(至少这是代码为了编译应该做的)并将其添加到 child
.
的向量中
现在,当对 operator+
returns 的调用被销毁时,temp
中的向量包含指向不存在对象的指针。
您可以通过使用 shared_ptr
将元素存储在向量中来解决此问题。请注意,如果引用循环是可能的,您应该小心地用 weak_ptr
打破这些循环(我没有在下面的代码中包含它的实现)。最终代码可能如下所示:
class DoubleWrap {
public:
static int id;
DoubleWrap(double value) : value(value), myid(++id) {}
double value;
int myid;
std::vector<std::shared_ptr<DoubleWrap>> parents;
DoubleWrap operator+(const DoubleWrap& x) const {
DoubleWrap result(this->value + x.value);
setParents(*this, result);
setParents(x, result);
return result;
}
static void setParents(const DoubleWrap& parent, DoubleWrap& child) {
child.parents.push_back(std::make_shared<DoubleWrap>(parent)); // makes a copy of parent
}
void printTree() const {
std::cout << "[" << this->myid << "]-(";
for (const auto& elem: this->parents)
std::cout << elem->myid << "," << elem.get() << ",";
std::cout << ")" << std::endl;
for (const auto& elem: this->parents)
elem->printTree();
}
};
int DoubleWrap::id = 0;
所以我遇到了一些段错误,想知道是否有人可以更深入地向我解释这是如何工作的。
我有一个围绕数字变量的包装器 class,我正在尝试构建表达式的计算树。这是一个示例代码:
class DoubleWrap{
public:
static int id;
DoubleWrap(double value){this->value = value;myid=++id;}
double value;
int myid;
std::vector<DoubleWrap*> parents;
DoubleWrap operator+(DoubleWrap& x){
DoubleWrap result(this->value + x.value);
setParents(*this,result);
setParents(x,result);
return result;
}
void setParents(DoubleWrap& parent,DoubleWrap& child){
child.parents.push_back(&parent);
}
void printTree(){
std::cout<< "[" << this->myid << "]-(";
for (auto& elem: this->parents)
std::cout<< elem->myid << "," << elem <<",";
std::cout<<")"<<std::endl;
for (auto& elem: this->parents)
elem->printTree();
}
}
我遇到的问题是像 x = a+b+c+d 这样的表达式;当我尝试寻找 x 的 parents 时,它有 2 个 parents,但 parents[0].parents[0] 为零,例如由于某种原因,指向分配位置的指针不起作用或分配的内存被破坏?
如果有人可以就解决方法以及为什么会发生这种情况向我提供建议,我将非常感兴趣。
举个关于这段代码的例子:
DoubleWrap dw(12.6);
DoubleWrap dw2(12.5);
DoubleWrap dw3(12.4);
DoubleWrap dw4(12.3);
DoubleWrap a = dw + dw2 + dw3;
DoubleWrap b = a + dw+ dw2+ dw3 + dw4;
b.printTree();
我期望输出:
[10]-(9,0x13a4b50,4,0x7fff5bdb62f0,)
[9]-(8,0x13a4b00,3,0x7fff5bdb62c0,)
[8]-(7,0x13a49f0,2,0x7fff5bdb6290,)
[7]-(6,0x7fff5bdb6320,1,0x7fff5bdb6260,)
[6]-(5,0x13a4db0,3,0x7fff5bdb62c0,)
[5]-(1,0x7fff5bdb6260,2,0x7fff5bdb6290,)
[1]-()
[2]-()
[3]-()
[1]-()
[2]-()
[3]-()
[4]-()
但我得到的结果(通常在不同的运行中不同):
[10]-(9,0x7ffffd5e2f00,4,0x7ffffd5e2de0,)
[9]-(33,0x1c6da10,3,0x7ffffd5e2db0,)
Process finished with exit code 139
我的猜测是运算符的 return 实际上复制了 DoubleWrap 变量,因此 parents 中的指针指向的值超出范围并释放内存?
临时解决方案是return参考,但问题是为什么以及是否有合适的解决方案?
PS: 修复了之前我得到的一个错误,是 setParents 的错误。
您的代码: DoubleWrap 运算符+(DoubleWrap& x){ DoubleWrap result(this->value + x->value); 如果 x 是指向 DoubleWrap class 的指针,那将是正确的,但是您已将 x 编码为 DoubleWrap class 对象而不是指针,因此您的代码 应该读 : DoubleWrap 运算符+(DoubleWrap& x){ DoubleWrap result(this->value + x.value);
您的问题是您要将指向 临时对象 的指针添加到向量中。
DoubleWrap a = dw + dw2 + dw3;
以上会先调用dw.operator+(dw2)
。这会创建一个临时对象,我们将其命名为 temp
。然后调用 temp.operator+(dw3)
。现在在 operator+
中有一个对 setParents
的调用,您将 temp
作为 parent
传递。然后获取 temp
的地址(至少这是代码为了编译应该做的)并将其添加到 child
.
现在,当对 operator+
returns 的调用被销毁时,temp
中的向量包含指向不存在对象的指针。
您可以通过使用 shared_ptr
将元素存储在向量中来解决此问题。请注意,如果引用循环是可能的,您应该小心地用 weak_ptr
打破这些循环(我没有在下面的代码中包含它的实现)。最终代码可能如下所示:
class DoubleWrap {
public:
static int id;
DoubleWrap(double value) : value(value), myid(++id) {}
double value;
int myid;
std::vector<std::shared_ptr<DoubleWrap>> parents;
DoubleWrap operator+(const DoubleWrap& x) const {
DoubleWrap result(this->value + x.value);
setParents(*this, result);
setParents(x, result);
return result;
}
static void setParents(const DoubleWrap& parent, DoubleWrap& child) {
child.parents.push_back(std::make_shared<DoubleWrap>(parent)); // makes a copy of parent
}
void printTree() const {
std::cout << "[" << this->myid << "]-(";
for (const auto& elem: this->parents)
std::cout << elem->myid << "," << elem.get() << ",";
std::cout << ")" << std::endl;
for (const auto& elem: this->parents)
elem->printTree();
}
};
int DoubleWrap::id = 0;