【问题标题】:Can the object be destroyed earlier, to make its storage memory be reused by subsequent objects?是否可以提前销毁对象,使其存储内存被后续对象重用?
【发布时间】:2015-02-03 22:10:06
【问题描述】:

C++:能否提前销毁对象,让后续对象重用其存储内存?

在一段 C++ 代码中,在前半部分,使用了对象 a、b; 在后半部分,创建和使用对象 c、d。

由于对象 a、b 占用大量内存,我想在前半部分完成时手动销毁对象 a、b。

我知道我可以使用new,delete来实现它。

但是如果我不使用 new,并且仍然想更早地销毁对象(也就是说,在其范围结束之前),我可以手动调用它的析构函数来销毁它吗?这样那部分内存就可以被对象 c 和 d 重用。 (我不需要释放内存,因为可以重用。

这是一个伪代码:

monsterClass a, b;
dragonClass c, d;
int i,j,k,l;

a = monsterClass(1000, 2000);
b = monsterClass(2000, 3000);
i = processMethod1(a, b);
j = ...;
k = ...;
l = ...;


// here, I want to destroy a, b, since they are not used any more, while occupy memory.
// The above half part and the below half part use many common variables. 
// So it seems scope {} method makes it inconvenient, 
// since I don't want to create a function with too many parameters.
// I don't want to use new or delete here. I hope it looks simple and not prone to error
// So can I use: ~a, ~b here?

c = dragonClass(400, 3000);
d = dragonClass(500, 4000);
processMethod2(c, d, i);
j = ...;
k = ...;
l = ...;

[Update 1] 所以大多数人建议使用范围,这是一个好方法。 我还是很好奇,我可以在那里使用 ~a 和 ~b 吗? 我认为这似乎也是一种可行且方便的方式。

[更新 2] 我想出了另一种情况。在这种情况下,不同变量的作用域是交织在一起的!就像这样:a 的范围与 b 的范围有重叠,但它们不包括关系。它是部分重叠的关系。 在这种情况下,这是否意味着无法使用范围? 最后的手段是使用new和delete,对吧?

【问题讨论】:

  • 请添加代码示例来解释为什么必须在对象在其范围结束之前销毁对象。您可以随时添加额外的{} 来定义更小的范围。
  • You can manually call the destructor of the original object, and then use placement new to create a new object on top of that memory。如果您这样做,请清楚地记录事情,因为它可能会严重混淆/误导代码的读者。
  • 你能把这两部分实现为单独的函数吗?或者在一个函数中单独的块?这将比手动控制简单得多(尽管在某种程度上这是可能的,如果你真的需要的话)。
  • 在开始使用新放置之前,请检查您的类如何处理内存。他们是否在内部分配内存(例如在构造函数中使用 new)?他们自己占据大面积,还是他们的成员占据?
  • @timrau, Mike Seymour, 上半部分和下半部分使用了许多公共变量。所以看起来 scope {} 方法很不方便,因为我不想创建一个参数太多的函数。

标签: c++ object-destruction


【解决方案1】:

作为你的代码 sn-p,你可以写成

int i,j,k,l;

{
  monsterClass a(1000, 2000);
  monsterClass b(2000, 3000);
  i = processMethod1(a, b);
  j = ...;
  k = ...;
  l = ...;
}

// here, you want to destroy a, b, since they are not used any more, while occupy memory.

dragonClass c(400, 3000);
dragonClass d(500, 4000);
processMethod2(c, d, i);
j = ...;
k = ...;
l = ...;

// you could use the same technique if there are still e, f or so

【讨论】:

  • 谢谢。我提出了另一种情况。在这种情况下,不同变量的作用域是交织在一起的!就像这样:a 的范围与 b 的范围有重叠,但它们不包括关系。它是部分重叠的关系。这种情况下,最后的办法就是用new和delete吧?
【解决方案2】:

你可以把它分解成更小的函数:

void part1() {
    monsterClass a, b;
    a = monsterClass(1000, 2000);
    b = monsterClass(2000, 3000);

    processMethod1(a, b);
}

或更大的函数中的块

{
    monsterClass a, b;
    // and so on
}
{
    dragonClass c, d;
    // and so on
}

或使用临时工

processMethod1(
    monsterClass(1000, 2000);
    monsterClass(2000, 3000);
);

如果您正在做的事情太复杂以至于这些都不合适,您可以使用 union 或 placement-new;细节会很繁琐,具体取决于您的奇怪要求。

【讨论】:

  • 上半部分和下半部分使用了很多公共变量。所以看起来 scope {} 方法很不方便,因为我不想创建一个参数太多的函数。我更喜欢使用手动管理它。有可能吗?
  • @user1914692:我不认为这会带来特别的不便。您必须在内部块之外声明公共变量;或者也许将它们包装在一个类中,并将其传递给函数。正如我所说,使用 union 或 placement-new 进行手动管理是可能的;但是很繁琐,并且取决于您奇怪要求的细节。在诉诸这种怪异之前,我会努力使用常规范围。
  • 你是对的。您的答案与 timrau 的相似。我可以将公共变量放在这些块之外。
【解决方案3】:

使用placement new并手动调用析构函数:

{
  char memory[std::max(sizeof(A),sizeof(B))];

  A* pA = new (memory) A();
  // use `pA`
  pA->~A(); // destruct A

  B* pB = new (memory) B();
  // use `pB`
  pB->~B(); // destruct B
} // `memory` goes out of scope

我建议阅读关于 operator new 的优秀资源:http://en.cppreference.com/w/cpp/language/new

【讨论】:

  • 听起来有点复杂。我希望用一个简单的。
【解决方案4】:

您可以使用大括号手动控制堆栈上对象的生命周期。

void foo()
{
    int x = 5;
    int y = 2;

    {          // This introduces a new scope
    int z = 3;
    }          // After this brace, z is now out of scope

    int a = x + y;
}

但请注意,一旦变量超出范围,则不会指定再次使用此内存。仅仅因为我声明了另一个名为 aint,并不意味着它将分配到 z 以前的地址。

【讨论】:

  • 我不在乎新变量是否准确地利用了旧变量的内存。但我希望编译器足够聪明,可以利用废弃变量的内存。现代编译器是这样吗?
  • 是的,一旦变量超出范围,使用我展示的方法或 Mike 或 erenon 的解决方案,该内存就可以免费用于其他对象。我只是想确保您知道该特定位置不一定会立即重复使用。
猜你喜欢
  • 2012-11-17
  • 2016-05-05
  • 2021-11-08
  • 2015-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-20
相关资源
最近更新 更多