以下是否定义明确?
#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
在语义上(故意?)指向新对象,而第一个已经消失,因此可以使用&#34; as一个void*
&#34;。但是第二个对象是在完全相同的地址构造的,因此p
的位模式表示新对象的地址。
COMMENT
new (p) Const(2)
删除存储在p
的旧对象,因此指针不再有效,除非作为指向存储的指针(void*
)。< / p>
我希望将p
的值恢复为Const*
。
评论2
在p->~Const()
或memset (p, 0, sizeof *p)
之后,很明显p
未指向有效对象,因此p
只能用作存储指针({{ 1}}或void*
),例如重建另一个对象。此时不允许char*
。
这里旧物体的拆除是由新物体的构造者完成的,但我不认为这会产生影响。
我的直觉是:在任何情况下,旧对象都消失了,p->get0()
指向旧对象,而不是新对象。
我正在寻找基于标准的确认或驳斥。
另见
我在C和C ++中提出了与指针基本相同的问题:
请在回答之前阅读这些讨论&#34;这很荒谬&#34;。
答案 0 :(得分:5)
(将社区维基纳入dyp的评论3.8/7是非常重要的;虽然我之前的分析是正确的,但我会说很多相同的事情,因为代码被破坏了,忽略了3.8 / 7我自己)
Const *q,*p = new Const(1);
new (p) Const(2);
new(p) Const(2);
行会覆盖使用Const(1)
构建的对象。
memcpy (&q, &p, sizeof p);
这相当于q = p;
。
cout << q->i;
这会访问q->i
成员2
。
有些值得注意的事情是:
std::memcpy
是一种将p
分配给q
的难看方式......虽然在3.9 / 3下是合法的:对于任何简单的可复制类型
T
,如果指向T
的两个指针指向不同的T
对象obj1
和obj2
,则obj1
}obj2
是基类子对象,如果构成obj1
的基础字节(1.7)被复制到obj2
,obj2
随后将保持与{相同的值{1}}。 [例如:
obj1
只要程序不依赖于前者析构函数的副作用,就可以用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(1)
对象。没有按&#39;吨
(正如下面评论中提到的dyp)使用Const(2)
对Const(2)
对象的持续访问在3.8 / 7的第三点是非法的:
指向原始对象的指针[...]可用于操作新对象,如果...
- 原始对象的类型不是
p
- 限定的,如果是类类型,则不包含任何类型为const
的非静态数据成员 - 限定或引用类型。 ..
const
- 而不是q
来访问p
可能是必要的,以避免基于假定的i
知识进行编译器优化。至于你的评论:
请注意,在构建第二个
i
之后,Const
在语义上(故意?)指向新对象,而第一个已经消失,因此可以使用&#34; asp
&#34;。
鉴于您在void*
中包含的地址放置了一个新对象,p
肯定会指向新创建的对象,并且非常有意,但它无法用于如上所述在3.8 / 7下操纵该对象。
鉴于你似乎有一个&#34;语义指向&#34;那些在C ++中没有定义的那部分声明的真实性在你自己的脑海里。
&#39;在构建第二个p
后,Const
... 可用&#34;作为p
&#39; 制作没有任何意义......它不像以前那样可以用作任何东西。
但第二个对象是在完全相同的地址构造的,因此
void*
的位模式代表新对象的地址。
当然,但你的评论表明你认为&#34;位模式&#34;在某种程度上与指针的值不同,适用于p
的赋值,这是不正确的。
=
删除存储在new (p) Const(2)
的旧对象,因此指针不再有效,除非作为指向存储的指针(p
)。
&#34;擦除&#34;这是一个奇怪的术语...覆盖会更有意义。正如上面提到并解释的那样,3.8 / 7表示你不应该操纵&#34;对象void*
指向放置new之后,但指针的值和类型不受placmeent new的影响。就像您可以使用指向任何类型的指针调用p
一样,展示位置 - f(void*)
不需要知道或关心new
表达式的类型。
在
p
或p->~Const()
之后,很明显memset (p, 0, sizeof *p)
未指向有效对象,因此p
只能用作存储指针({{ 1}}或p
),例如重建另一个对象。此时不允许void*
。
大部分内容都是正确的,如果只有&#34; char*
才能使用&#34;你的意思是那时p->get0()
的值而不是指针本身(当然也可以指定)。并且您尝试使用p
/ p
事物过于聪明 - void*
仍为char*
,即使它仅使用p
通过放置new并不关心指针类型。
&#34;我希望将
Const*
的值恢复为p
。&#34;
Const*
的值在首次初始化后未更改。展示位置 - p
使用该值 - 它不会修改它。因为什么都没有丢失,没有什么可以恢复的。也就是说,dyp强调不需要使用new
来操纵对象,因此虽然价值没有丢失,但也不能直接使用。
答案 1 :(得分:4)
这只是作为@Tony D答案的附录,关于
的旧对象
new (p) Const(2)
删除存储在p
我认为你需要区分一个对象和一个“实例”的概念。
[...]对象是存储区域。[...]
[N4431§1.8/ 1]
因此指针p
指向一个存储区域,其中包含一个“实例”的位模式,在放置新的之前,一些不同的位模式是一个不同的,但构造良好的“实例”的正确(相同)类型。
因此,在p
指向的位置,有一个有效的对象,当从q
分配q
时,它指向它。虽然如其他答案所述,但不会通过p
访问它。