我正在阅读Andrei的Modern C ++ Design,其中提到了
"Pointers to allocated objects does not have a value semantics"
对于Value语义示例,提到'int'是完美的。 所以
int x = 200, y;
y = x;
我的问题?
1)要考虑的参数是什么,以便我可以声称这是一个“价值语义”。 2)为什么指向对象的指针并不声称是“价值语义”。
我的理解是什么?
如果你不能将变量复制到另一个与原始变量完全分离的变量,那就是'值语义'。
如果我的理解错了,请纠正我吗?并提供一些简单的例子。
答案 0 :(得分:2)
引用似乎脱离了背景。
普通指针确实有值语义:
char const *x = "x", *y;
y = x;
这些是没有值语义的C ++引用。它们可以初始化但不能重新分配。
引用可能是指函数参数传递:函数的参数可以通过值(复制)或引用传递。在此上下文中的引用意味着通过指针传递或接受引用。在此上下文中,通过引用传递的对象没有值语义,即,没有完成对象的复制,并且当函数返回时,函数所做的对对象的所有更改都是可见的。但是,在某种意义上,所有函数参数都是副本:调用者提供的参数被复制到被调用函数的堆栈帧中(或作为优化的寄存器传递)。通过引用传递从根本上意味着传递对象的地址(通过指针或引用)。无论复制一个地址多少次,它仍然指向同一个对象。
答案 1 :(得分:2)
短语“价值语义”被广泛使用,但通常相当松散地定义。我认为斯科特迈耶斯的定义与任何定义一样好:“就像投注一样。”
换句话说,具有值语义的对象是一个可以像int一样处理的对象,如果这样做,它通常不会做任何令人惊讶的事情。复制,分配,适用的操作员等都是“正常工作”。您创建的每个“事物”都独立于其他任何事物,因此(例如)x + y
不会更改x
,就像您使用x += y
一样(完全不是)例如,字符串类的公平数量已经完成。
答案 2 :(得分:2)
Stepanov给出了以下值语义定义(他称之为常规类型)
T a = b; assert(a == b); // 1
T a; a = b; assert(a == b); // 2
T a = c; T b = c; a = d; assert(b == c); // 3
T a = c; T b = c; zap(a); assert(b == c && a != b); // 4
即,具有值语义的类型是DefaultConstructible,CopyConstructible,Assignable和EqualityComparible(属性1和2)。此外,
为
c
和a
分配相同的值b
后,我们预计 能够修改a
而不更改b
的值(属性 3)。如果zap
是一个总是改变其值的操作 操作数,我们希望b
和c
不能简单地保持平等 因为他们的价值观与a
一起改变了,而是因为 更改a
的值并未改变他们的属性(属性4)。
具有引用语义的类型可以服从1和2,但不能服从3和4(即,对指向或引用相同值的一个或多个对象的修改会影响所有这些对象)。
所有内置类型都遵循值语义,并且修改是本地化的。这使它们成为例如非常适合纯函数和并行编程。使用引用语义(例如具有虚函数的对象),更改不再本地化。
T* a = c; T* b = c; a = d; assert(b == d); // 5
T* a = c; T* b = c; zap(a); assert(b != c && a == b); // 6
答案 3 :(得分:1)
您的理解是正确的。这是一个例子:
string* str_rptr = new string("hello");
string* str2_rptr = str_rptr;
str2_rptr->replace(0,5,"goodbye");
std::cout << *str_rptr << std::endl;
这个片段的输出会打印“再见”而不是“你好”。在您提供的“完美int”示例之后,此代码:
y = 400;
std::cout << x << std::endl;
将打印出“200”。重要的一点是,复制变量并不会阻止对一个变量进行更改。
答案 4 :(得分:1)
换句话说,对象的指针(或引用)不是新的唯一对象,但指针指向您指向的原始对象。因此,你必须小心指针,所以你要确保你知道你指向的是什么以及如果你修改了指针所指向的东西会改变什么。
相反,我们无法一直完全使用“值语义”(至少在C语言中),因为你无法编写一个修改传入值内容的函数 - 这有时会很方便......
答案 5 :(得分:1)
值语义意味着,如果你是设置a = b
然后a是b的副本,具有相同的值但与b分离,因此如果你在那之后仍然包含b的原始值:
int a, b = 5;
a = b; //a is 5 now
b = 7; //a is still 5!
//in contrast to pointers:
int* pb = new int(5);
int* pa = pb; //*a is 5 now
*pb = 7; //*a is not 5 any more, it's 7!
在该示例中,a和b未分离,因此没有值语义。
答案 6 :(得分:0)
这里的大多数答案混淆了“指针”和“指针指向的对象”。指针具有值语义:如果将一个指针复制到另一个指针,则修改第一个指针,第二个指针不变。
答案 7 :(得分:0)
我能找到的最简洁的解释是:“值语义意味着复制/克隆的修改不会影响原始对象”。指针显然违反了这一点。不是自己(因为你可以很容易地复制指针而不是伤害其他指针)本身,而是他们指向的对象。