cur*_*guy 4 c++ const placement-new memcpy language-lawyer
以下是否定义明确?
#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;
}
Run Code Online (Sandbox Code Playgroud)
注意,在构造第二个之后Const,p在语义上(故意?)指向新对象,并且第一个已经消失,因此它可以"用作void*".但是第二个对象是在完全相同的地址构造的,因此位模式p表示新对象的地址.
评论
new (p) Const(2)擦除存储在的旧对象p,因此指针不再有效,除非作为指向storage(void*)的指针.
我想恢复p作为一个的价值Const*.
评论2
在任何一个p->~Const()或memset (p, 0, sizeof *p)很明显p没有指向有效对象之后,因此p只能用作存储(void*或char*)的指针,例如重建另一个对象.此时p->get0()是不允许的.
这里旧对象的拆除是由新对象的构造函数完成的,但我认为这不会产生影响.
我的直觉是:在任何情况下,旧对象都消失了,并p指向旧对象,而不是新对象.
我正在寻找基于该标准的确认或驳斥.
也可以看看
我在C和C++中提出了与指针基本相同的问题:
在回答"这太荒谬了"之前,请先阅读这些讨论.
(将社区维基纳入dyp的评论3.8/7是非常重要的;虽然我之前的分析是正确的,我会说很多相同的事情,关于破坏的代码,我自己忽略了3.8/7)
Const *q,*p = new Const(1);
new (p) Const(2);
Run Code Online (Sandbox Code Playgroud)
该new(p) Const(2);行将覆盖已构造的对象Const(1).
memcpy (&q, &p, sizeof p);
Run Code Online (Sandbox Code Playgroud)
这相当于q = p;.
cout << q->i;
Run Code Online (Sandbox Code Playgroud)
这将访问该q->i成员2.
有些值得注意的事情是:
std::memcpy是一种难以分配的p方式q......虽然在3.9/3下是合法的:对于任何平凡复制的类型
T,如果两个指针T指向不同T对象obj1和obj2,其中既不obj1也不obj2是碱基-类子对象,如果构成底层字节(1.7)obj1被复制到obj2,obj2随后应保持相同的值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
Run Code Online (Sandbox Code Playgroud)
只要程序不依赖于前者析构函数的副作用,就可以覆盖旧Const(1)对象Const(2).
(正如dyp在下面的评论中指出的)在3.8/7的第三点下,持续访问Const(2)使用对象p是非法的:
指向原始对象的指针可用于操纵新对象,如果......
- 原始对象的类型不是
const-qualified,如果是类类型,则不包含任何类型为const-qualified或引用类型的非静态数据成员...
q- 而不是p- 访问i可能是必要的,以避免基于推测的知识的编译器优化i.至于你的评论:
注意,在构造第二个之后
Const,p在语义上(故意?)指向新对象,并且第一个已经消失,因此它可以"用作void*".
鉴于您在包含的地址中放置了一个新对象p,p大多数肯定会指向新创建的对象,并且非常有意,但它不能用于在3.8/7下操作该对象,如上所述.
鉴于你似乎有一个"语义指向"的概念,这个概念在C++中没有定义,这个陈述的部分真实在你自己的脑海里.
"在构建第二个之后Const,p...... 可以使用"作为一个void*"毫无意义"......它不像以前那样可以用作任何东西.
但是第二个对象是在完全相同的地址构造的,因此位模式
p表示新对象的地址.
当然,但是你的评论表明你认为"位模式"在某种程度上与指针的值不同,适用于赋值=,这是不正确的.
new (p) Const(2)擦除存储在的旧对象p,因此指针不再有效,除非作为指向storage(void*)的指针.
"擦除"对它来说是一个奇怪的术语......覆盖会更有意义.正如上面提到并解释的dyp,3.8/7表示你不应该p在放置new之后"操纵"对象指向,但是指针的值和类型不受placmeent new的影响.就像你可以f(void*)使用指向任何类型的指针调用一样,放置 - new不需要知道或关心p表达式的类型.
在任何一个
p->~Const()或memset (p, 0, sizeof *p)很明显p没有指向有效对象之后,因此p只能用作存储(void*或char*)的指针,例如重建另一个对象.此时p->get0()是不允许的.
大多数情况都是如此,如果" p只能使用",则表示当时的值p而不是指针本身(当然也可以指定).并且你试图对void*/ char*thing 有点过于聪明- p仍然是一个Const*,即使它只用于不关心指针类型的placement new.
"我希望恢复
p作为一个的价值Const*."
p首次初始化后,该值未更改.placement- new使用值 - 它不会修改它.没有什么可以恢复,因为什么都没有丢失.也就是说,dyp强调不需要使用p来操纵对象,所以虽然值没有丢失,但它也不能直接使用.
| 归档时间: |
|
| 查看次数: |
304 次 |
| 最近记录: |