重载的operator new中初始化类成员是否未定义?

发布于 2024-11-17 14:41:27 字数 430 浏览 2 评论 0原文

举一个小例子,我试图找出变量是否在堆上分配:

struct A
{
  bool isOnHeap;
  A () {}  // not touching isOnHeap
 ~A () {}

  void* operator new (size_t size)
  {
    A* p = (A*) malloc(size);
    p->isOnHeap = true;  // setting it to true
    return p;
  }
  void operator delete (void *p) { free(p); }
};

它给出了 的预期结果g++-4.5(带有堆栈对象的警告)。是否定义不明确 要做这样的操作吗?

Take a small example where, I am trying to find out if a variable is allocated on heap or not:

struct A
{
  bool isOnHeap;
  A () {}  // not touching isOnHeap
 ~A () {}

  void* operator new (size_t size)
  {
    A* p = (A*) malloc(size);
    p->isOnHeap = true;  // setting it to true
    return p;
  }
  void operator delete (void *p) { free(p); }
};

It gives expected result in g++-4.5 (with warning for stack object). Is it ill defined
to do such operations ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦萦几度 2024-11-24 14:41:27

您无法在重载的operator new 中初始化类成员,因为对象的生命周期尚未开始。您只能在对象构造期间初始化成员。

您无法保证实现不会擦除 operator new 返回时间和对象构造开始时间之间的内存,或者在对象构造期间,标准指定具有不确定值的成员(例如,因为它们是 POD 并且没有在构造函数中显式初始化,如 isOnHeap),但实现不会故意将其设置为某些内容。

请注意,A 有一个不平凡的构造函数(它是用户声明的),因此它的生命周期不会在分配对象存储时开始(ISO/IEC 14882:2003, 3.8 [basic .life] / 1) 并且如果程序使用指向对象存储的指针来访问非静态数据成员 (3.8 / 5),则程序具有未定义的行为。即使 A 是 POD 类型,它在 new-expression 完成后的值仍然是不确定的,而不一定与存储中字节中的值相关对于在计算 new-expression 之前的对象。

You can't initialize class members in an overloaded operator new because the object's lifetime hasn't started. You can only initialize members during the construction of the object.

You have no guarantee that the implementation won't wipe the memory between the time operator new returns and the time the object's construction starts or that during object construction members that are specified to have an indeterminate value by the standard (e.g. because they are POD and not explicitly initialized in the constructor like isOnHeap) aren't deliberately set to something by the implementation.

Note that A has a non-trivial constructor (it is user-declared), so its lifetime doesn't start when the storage for the object is allocated (ISO/IEC 14882:2003, 3.8 [basic.life] / 1) and the program has undefined behavior if it uses a pointer to the storage for the object to access a non-static data member (3.8 / 5). Even if A was a POD type, it's value after the completion of the new-expression would still be indeterminate rather than necessarily being related to the values in the bytes in the storage for the object before the new-expression was evaluated.

小红帽 2024-11-24 14:41:27

正如 Charles 所说,对象只有在被更新后才具有生命周期,因此在 new 的实现中设置数据是相当危险的。

此外,当您的开发人员使用 Lint 之类的工具时,它很有可能会抱怨成员 isOnHeap 未在构造函数中初始化。如果有人认为“嘿,Lint 是对的,让我们在 A 的构造函数中初始化 isOnHeap”,这将破坏您尝试实现的机制。

还有第二种情况你可能没有想到。假设有人这样写:

class MyClass
   {
   public:
      ...
   private:
      struct A m_a;
   };

int main()
   {
   MyClass *myVariable = new MyClass();
   }

那么你的 new 实现将不会被调用。尽管如此,A 的实例还是分配在堆上(作为 MyClass 实例的一部分)。

你能解释一下为什么你想知道堆上是否分配了某些东西吗?也许还有另一种更优雅的解决方案可以解决您的问题。

As Charles said, the object only comes to lifetime after it has been newed, so setting data within your implementation of new is rather dangerous.

Also, when your developers use tools like Lint, there's a big chance that it complains that the member isOnHeap is not initialized in the constructor. If then someone thinks "hey, Lint is right, let's initialize isOnHeap in the constructor of A", this will undermine the mechanism that you try to achieve.

There is a second case of which you probably didn't think. Suppose that someone writes this:

class MyClass
   {
   public:
      ...
   private:
      struct A m_a;
   };

int main()
   {
   MyClass *myVariable = new MyClass();
   }

Then your implementation of new will not be called. Nevertheless the instance of A is allocated on the heap (as part of the MyClass instance).

Can you explain why you want to know whether something has been allocated on the heap or not? Maybe there's another, more elegant solution to your problem.

荒芜了季节 2024-11-24 14:41:27

即使不考虑运算符 new 本身(这是非标准的,我什至会说丑陋,但知道某些特定编译器的确切细节,它可能是可行的),还有另一个问题,这使得它毫无用处:你没有保证在堆栈上分配时 od isOnHeap 的值不会为 true。堆栈未初始化,并且可以在其中找到之前完成的函数调用中的任何垃圾。

Even when not considering the operator new itself (which is nonstandard and I would even say ugly, but knowing the exact details of some particular compiler it might be workable), there is another problem with this, which renders it useless anyway: You have no guarantee the value od isOnHeap will not be true when allocated on the stack. The stack is not initialized and any garbage from function invocations done before can be found there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文