问题描述
以下定义是否明确?
#include <iostream>
#include <string.h>
using namespace std;
struct Const {
const int i;
Const (int i) : i(i) {}
int get0() { return 0; } // best accessor ever!
};
int main() {
Const *q,*p = new Const(1);
new (p) Const(2);
memcpy (&q, &p, sizeof p);
cout << q->i;
return 0;
}
请注意,在构造第二个Const
之后,p
不会在语义上(有意地?)指向新对象,而第一个消失了,因此可以用作void*
"使用.但是第二个对象是在完全相同的地址处构造的,因此p
的位模式表示新对象的地址.
Note that after construction of second Const
, p
doesn't semantically (intentionally?) points to new object, and the first is gone, so it is usable "as a void*
". But the second object is constructed at the exact same address, so the bit pattern of p
represents the address of the new object.
评论
new (p) Const(2)
会删除存储在p
中的旧对象,因此该指针不再有效,除了作为指向存储(void*
)的指针之外.
new (p) Const(2)
erase the old object stored at p
, so the pointer is not valid anymore, except as a pointer to storage (void*
).
我想将p
的值恢复为Const*
.
评论2
在p->~Const()
或memset (p, 0, sizeof *p)
之后,很明显p
并不指向有效对象,因此p
只能用作存储的指针(void*
或char*
),对于重建另一个对象的示例.那时不允许p->get0()
.
After either p->~Const()
or memset (p, 0, sizeof *p)
it is clear that p
does not point to a valid object, so p
can only be used as pointer to storage (void*
or char*
), for example to reconstruct another object. At that point p->get0()
is not allowed.
在这里,旧对象的拆卸是由新对象的构造函数完成的,但我认为这没有什么不同.
Here the demolition of the old object is done by the constructor of the new one, but I don't think that makes a difference.
我的直觉是:无论如何,旧对象都消失了,而p
指向旧对象,而不是新对象.
My intuition is that: In any case, the old object is gone, and p
points to the old object, not the new one.
我正在根据标准寻找确认或反驳.
另请参见
我在C和C ++中问过关于指针的基本相同的问题:
I have asked essentially the same question about pointers, in C and C++ :
- Dereferencing an out of bound pointer that contains the address of an object (array of array)
- Is memcpy of a pointer the same as assignment?
- Are pointer variables just integers with some operators or are they "mystical"?
在回答这很荒谬"之前,请先阅读这些讨论.
Please read these discussions before answering "this is ridiculous".
推荐答案
(使社区Wiki合并dyp的3.8/7版评论是非常重要的;虽然我先前的分析是正确的,但我对代码也有很多相同的看法打破了,我自己忽略了3.8/7)
(making community-wiki as incorporating dyp's comment re 3.8/7 is very significant; while my earlier analysis was correct I would have said much the same things about code that was broken, having overlooked 3.8/7 myself)
Const *q,*p = new Const(1);
new (p) Const(2);
new(p) Const(2);
行覆盖了用Const(1)
构造的对象.
The new(p) Const(2);
line overwrites the object that had been constructed with Const(1)
.
memcpy (&q, &p, sizeof p);
这等效于q = p;
.
cout << q->i;
这将访问q->i
成员,该成员将为2
.
This accesses the q->i
member, which will be 2
.
有些值得注意的事情是:
The somewhat noteworthy things are:
-
std::memcpy
是将p
分配给q
的一种丑陋方式...虽然在3.9/3以下版本是合法的:
std::memcpy
is an ugly way to assignp
toq
... it is legal though under 3.9/3:
T* t1p;
T* t2p;
// provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
// at this point, every subobject of trivially copyable type in *t1p contains
// the same value as the corresponding subobject in *t2p
-
允许使用
Const(2)
覆盖旧的Const(1)
对象,只要程序不依赖于前者的析构函数的副作用即可,The overwriting of the old
Const(1)
object withConst(2)
is allowed as long as the program doesn't depend on side effects of the former's destructor, which it doesn't.(如下面的注释中的dyp所示)持续使用
p
访问Const(2)
对象是非法的:(as dyp noted in comments below) ongoing access to the
Const(2)
object usingp
is illegal under 3.8/7's third point:- 原始对象的类型不是
const
限定的,并且,如果是类类型,则不包含任何类型是const
限定的非静态数据成员或引用类型...
- the type of the original object is not
const
-qualified, and, if a class type, does not contain any non-static data member whose type isconst
-qualified or a reference type ...
- 使用
q
-而不是p
-来访问i
可能是必要的,以避免基于对i
的了解而进行的编译器优化. - using
q
- rather thanp
- to accessi
is presumably necessary to avoid compiler optimisations based on presumed knowledge ofi
.
关于您的评论:
假设您在
p
中包含的地址处放置了一个新对象,p
很肯定确实指向了新创建的对象,但是在3.8/下不能使用该对象来操作该对象. 7以上.Given you placement-new an object at the address contained in
p
,p
most certainly does point to the newly created object, and very intentionally, but it can't be used to manipulate that object under 3.8/7 as above.鉴于您似乎有一个语义上指向"的概念,而C ++中并未定义这部分内容的真实性.
Given you seem to have a notion of "semantically pointing" that's not defined in C++ the truth of that part of the statement's in your own mind.
'在构造第二个
Const
之后,p
... 是可用的,因为void*
'毫无意义……它没有比以前更有用的了'after construction of second
Const
,p
...is usable "as avoid*
' makes no sense... it's not more usable as anything than it was beforehand.当然,但是您的注释表明您认为位模式"与指针的值在某种程度上有所区别,这适用于使用
=
进行赋值,这是不正确的.Of course, but your comments show you think "bit pattern" is somehow distinct from the value of the pointer as applies to assignment with
=
, which is not true.擦除"是一个奇怪的名词……覆盖将更有意义.正如dyp在上面指出和解释的那样,3.8/7表示您不应该操纵"对象
p
在新放置位置之后指向的对象,但是指针的值和类型不受新放置的指针的影响.就像您可以使用指向任何类型的指针来调用f(void*)
一样,placement-new
无需了解或关心p
表达式的类型."erase" is a strange term for it... overwrites would be more meaningful. As dyp noted and explained above, 3.8/7 says you shouldn't "manipulate" the object
p
points to after the placement new, but the value and type of the pointer are unaffected by the placmeent new. Much as you can callf(void*)
with a pointer to any type, the placement-new
doesn't need to know or care about the type of thep
expression.大多数情况都是如此,如果只能使用
p
"是指当时p
的值,而不是指针本身(当然也可以分配给指针).而且您正在尝试对void*
/char*
东西变得太聪明-p
仍然是Const*
,即使它仅用于不关心pointee类型的new放置. /p>Most of that's true, if by "
p
can only be used" you mean the value ofp
at that time rather than the pointer itself (which can be of course also be assigned to). And you're trying to be a little too clever with thevoid*
/char*
thing -p
remains aConst*
, even if it's only used by placement new which doesn't care about the pointee type.p
的值在首次初始化后未更改. placement-new
使用该值-不会对其进行修改.没有什么可以恢复的,因为什么也没有丢失.就是说,dyp强调了不必使用p
来操纵对象,因此,虽然该值没有丢失,但也不能按需要直接使用.The value of
p
was not changed after it was first initialised. placement-new
uses the value - it does not modify it. There's nothing to recover as nothing was lost. That said, dyp's highlighted the need not to usep
to manipulate the object, so while the value wasn't lost it's not directly usable as wanted either.这篇关于用相同类型的对象覆盖对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
- 原始对象的类型不是