用相同类型的对象覆盖对象 [英] Overwriting an object with an object of same type

查看:106
本文介绍了用相同类型的对象覆盖对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下定义是否明确?

#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 assign p to q... it is legal though under 3.9/3:

对于任何普通可复制类型T,如果两个指向T的指针指向不同的T对象obj1obj2,其中obj1obj2都不是基类子对象,如果组成obj1的基础字节(1.7)被复制到obj2,则obj2随后应保持与obj1相同的值. [示例:

For any trivially copyable type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a base-class subobject, if the underlying bytes (1.7) making up obj1 are copied into obj2, obj2 shall subsequently hold the same value as obj1. [ Example:

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 with Const(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 using p is illegal under 3.8/7's third point:

      指向原始对象[...]的指针可以用来操纵新对象,如果...

      pointer that pointed to the original object [...] can be used to manipulate the new object, if...

      • 原始对象的类型不是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 is const-qualified or a reference type ...

      • 使用q-而不是p-来访问i可能是必要的,以避免基于对i的了解而进行的编译器优化.
        • using q - rather than p - to access i is presumably necessary to avoid compiler optimisations based on presumed knowledge of i.
        • 关于您的评论:

          请注意,在构造第二个Const之后,p不会在语义上(有意地?)指向新对象,而第一个已消失,因此可以用作"void*".

          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*".

          假设您在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 a void*' makes no sense... it's not more usable as anything than it was beforehand.

          但是第二个对象是在完全相同的地址处构造的,因此p的位模式表示新对象的地址.

          But the second object is constructed at the exact same address, so the bit pattern of p represents the address of the new object.

          当然,但是您的注释表明您认为位模式"与指针的在某种程度上有所区别,这适用于使用=进行赋值,这是不正确的.

          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.

          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*).

          擦除"是一个奇怪的名词……覆盖将更有意义.正如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 call f(void*) with a pointer to any type, the placement-new doesn't need to know or care about the type of the p expression.

          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.

          大多数情况都是如此,如果只能使用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 of p 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 the void* / char* thing - p remains a Const*, even if it's only used by placement new which doesn't care about the pointee type.

          我想将p的值恢复为Const*."

          "I want to recover the value of p as a Const*."

          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 use p to manipulate the object, so while the value wasn't lost it's not directly usable as wanted either.

          这篇关于用相同类型的对象覆盖对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆