为什么点运算符的值在 C++ 中没有改变?
Why with dot operator value is not changed in c++?
我来自 Javascript 背景并且正在尝试使用 c++,我想在调用函数中改变数组中的结构成员,如下所示。
#include<iostream>
#include<vector>
using namespace std;
typedef struct Node{
int value;
Node(int val){
this->value = val;
}
};
void changeValueByDot(Node* p, int idx){
Node n = *(p + idx);
n.value = 54;
}
void changeValueByArrow(Node* p, int idx){
Node* n = (p + idx);
n->value = 32;
};
int main(){
vector<Node> v = {
Node(1),
Node(2)
};
changeValueByDot(v.data(), 1);
cout<<"After changing by dot:"<<v[1].value<<endl;
changeValueByArrow(v.data(), 1);
cout<<"After changing by arrow:"<<v[1].value<<endl;
return 0;
}
现在我的困惑是为什么点运算符不能进行永久更改而箭头运算符可以。
我对点的期望是首先到达获取节点的地方并更改其值。我不确定该位置的节点是否被复制以及更改是否在复制的节点中完成。
我尝试同时使用向量和固定大小的数组,结果相同。
请帮助我理解这一点。
提前致谢!
这一行:
Node n = *(p + idx);
变量n
是右侧节点的副本。修改 n.value
不会更改右侧引用的节点。
如果你想n
引用取消引用的节点,那么使用一个引用:
Node & n = *(p + idx);
// ^
现在对 n
的更改将反映在对 *(p + idx)
的更改中
请注意,当您这样做时这不是问题:
Node* n = (p + idx);
因为虽然 n
仍然是一个 copy,它是一个 pointer 的副本,并且修改 n->value
实际上会更改 p + idx
.
指向的同一对象的 value
成员
Java 没有对象类型的变量。 Java 有引用对象的变量。
这是因为 Java gc 要求对象存在于堆中,而且几乎从不将它们放在您放置它们的位置。在 C++ 术语中,Java 对象变量是奇特的智能指针。
void changeValueByDot(Node* p, int idx){
Node n = *(p + idx);
n.value = 54;
}
如果类型 Node
调用 n
,此代码将创建一个本地(在堆栈上)对象。
粗略的 Java “伪代码”等价物是:
void changeValueByDot(Node p, int idx){
Node n = (p + idx).clone();
n.value = 54;
}
或
void changeValueByDot(int reference p, int idx){
int n = p;
n = 54;
}
在第一种情况下,我们使 C++ 中对象的隐式复制显式化。在第二种情况下,我们使用 Java 不会隐式转换为引用的类型。
在这两种情况下,显然只修改了本地数据。所以 C++ 版本也是如此。
Java 缺少对象实例变量意味着它不对称地对待基元和对象。另一方面,C++ 对象的行为类似于原始对象。您可以在 C++ 中编写替换 int
并使其语义与基本 int 相同,但在引擎盖下它是一个可变大小的任意精度 bigint。
我来自 Javascript 背景并且正在尝试使用 c++,我想在调用函数中改变数组中的结构成员,如下所示。
#include<iostream>
#include<vector>
using namespace std;
typedef struct Node{
int value;
Node(int val){
this->value = val;
}
};
void changeValueByDot(Node* p, int idx){
Node n = *(p + idx);
n.value = 54;
}
void changeValueByArrow(Node* p, int idx){
Node* n = (p + idx);
n->value = 32;
};
int main(){
vector<Node> v = {
Node(1),
Node(2)
};
changeValueByDot(v.data(), 1);
cout<<"After changing by dot:"<<v[1].value<<endl;
changeValueByArrow(v.data(), 1);
cout<<"After changing by arrow:"<<v[1].value<<endl;
return 0;
}
现在我的困惑是为什么点运算符不能进行永久更改而箭头运算符可以。 我对点的期望是首先到达获取节点的地方并更改其值。我不确定该位置的节点是否被复制以及更改是否在复制的节点中完成。
我尝试同时使用向量和固定大小的数组,结果相同。
请帮助我理解这一点。 提前致谢!
这一行:
Node n = *(p + idx);
变量n
是右侧节点的副本。修改 n.value
不会更改右侧引用的节点。
如果你想n
引用取消引用的节点,那么使用一个引用:
Node & n = *(p + idx);
// ^
现在对 n
的更改将反映在对 *(p + idx)
请注意,当您这样做时这不是问题:
Node* n = (p + idx);
因为虽然 n
仍然是一个 copy,它是一个 pointer 的副本,并且修改 n->value
实际上会更改 p + idx
.
value
成员
Java 没有对象类型的变量。 Java 有引用对象的变量。
这是因为 Java gc 要求对象存在于堆中,而且几乎从不将它们放在您放置它们的位置。在 C++ 术语中,Java 对象变量是奇特的智能指针。
void changeValueByDot(Node* p, int idx){
Node n = *(p + idx);
n.value = 54;
}
如果类型 Node
调用 n
,此代码将创建一个本地(在堆栈上)对象。
粗略的 Java “伪代码”等价物是:
void changeValueByDot(Node p, int idx){
Node n = (p + idx).clone();
n.value = 54;
}
或
void changeValueByDot(int reference p, int idx){
int n = p;
n = 54;
}
在第一种情况下,我们使 C++ 中对象的隐式复制显式化。在第二种情况下,我们使用 Java 不会隐式转换为引用的类型。
在这两种情况下,显然只修改了本地数据。所以 C++ 版本也是如此。
Java 缺少对象实例变量意味着它不对称地对待基元和对象。另一方面,C++ 对象的行为类似于原始对象。您可以在 C++ 中编写替换 int
并使其语义与基本 int 相同,但在引擎盖下它是一个可变大小的任意精度 bigint。