2

我正在阅读 Andrei 的 Modern C++ Design,其中提到

"Pointers to allocated objects does not have a value semantics"

对于值语义示例,提到“int”是完美的。所以

int x = 200, y;
y = x;

我的问题?

1)要考虑的参数是什么,以便我可以声称它是“值语义”。?2)为什么指向对象的指针不声称是“价值语义”。

我明白了什么?

如果您不能将变量复制到与原始变量完全不同的另一个变量,那么这就是“值语义”。

如果我的理解有误,请纠正我?并提供一些简单的例子。

4

8 回答 8

2

引用似乎断章取义。

普通指针确实具有值语义:

char const *x = "x", *y;
y = x;

这些是没有值语义的 C++ 引用。它们可以被初始化但不能重新分配。

引用可能是指函数参数传递:函数的参数可以通过值(复制)或引用传递。在这种情况下,通过引用意味着通过指针传递或接受引用。在这种情况下,通过引用传递的对象没有值语义,即没有完成对象的副本,并且函数对对象所做的所有更改在函数返回时都是可见的。但是,从某种意义上说,所有函数参数都是副本:调用者提供的参数被复制到被调用函数的堆栈帧中(或作为优化传递到寄存器中)。通过引用传递基本上意味着传递对象的地址(通过指针或引用)。无论一个地址复制多少次,它仍然指向同一个对象。

于 2013-01-24T15:10:18.717 回答
2

短语“值语义”被广泛使用,但通常定义比较松散。我认为 Scott Meyers 的定义与任何人一样好:“​​像整数一样做”。

换句话说,具有值语义的对象是您可以将其视为 int 的对象,如果您这样做,它通常不会做任何令人惊讶的事情。复制、赋值、适用的运算符等等,都是“正常工作”。您创建的每个“事物”都独立于任何其他“事物”,因此(例如)x + y不会x像您使用过的那样发生变化(例如x += y,一个(完全不)公平数量的字符串类已经完成)。

于 2013-01-24T15:11:55.597 回答
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(property 3) 的值的情况下进行修改。ifzap是一个总是改变其操作数的值的操作,我们期望b并且c不会仅仅因为它们的值随着 's 一起改变而继续相等a,而是因为改变a's 的值并没有改变它们的值(属性 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
于 2013-01-24T15:44:23.283 回答
1

在此处查看价值语义

换句话说,指向对象的指针(或引用)不是一个新的唯一对象,而是指针指向您让它指向的原始对象。因此,您必须小心使用指针,以确保您知道您所指向的内容以及如果您修改指针所指向的内容会发生什么变化。

相反,我们不能一直完全使用“值语义”(至少在 C 中),因为您无法编写修改传入值内容的函数——这有时会很方便......

于 2013-01-24T15:14:37.910 回答
1

值语义意味着,如果你设置a = b了那么 a 是 b 的副本,具有相同的值但与 b 分离,因此如果你之后 b,a 仍然包含 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 没有分离,因此没有值语义。

于 2013-01-24T15:14:42.457 回答
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”。重要的一点是,复制一个变量不会阻止对一个变量的更改改变另一个。

于 2013-01-24T15:11:33.583 回答
0

对于您的问题,我能找到的最简洁的解释是:“值语义意味着对复制/克隆的修改不会影响原始对象”。指针显然违反了这一点。不是它们本身(因为您可以轻松地复制指针而不损害其他指针)本身,而是它们指向的对象。

于 2013-01-24T18:46:36.187 回答
0

这里的大多数答案都混淆了“指针”和“指针指向的对象”。指针具有值语义:如果将一个指针复制到另一个指针,则修改第一个指针,第二个指针不变。

于 2013-01-24T15:52:59.400 回答