【问题标题】:(Re)Initializing object without copy constructor in cpp(重新)在cpp中初始化没有复制构造函数的对象
【发布时间】:2019-02-12 08:09:22
【问题描述】:

这个问题是针对嵌入式系统的!

我有以下选项来初始化一个对象:

Object* o = new Object(arg);

这会将对象放入堆中并返回指向它的指针。我不喜欢在嵌入式软件中使用动态分配。

Object o = Object(arg);

这会在堆栈中创建一个新对象,然后将其复制到对象o 并在之后将其删除。如果对象大到足以放入 RAM 但不能放入堆栈,这可能会导致堆栈溢出。我已经看到关闭优化时会发生这种情况,我还没有探索过启用优化是否会有所不同。

Object o(arg);

这会创建对象而不进行复制,但是我怎样才能再次“初始化”o?

对于嵌入式,我更喜欢最后一个选项,因为不使用堆,并且堆栈中没有可以执行堆栈溢出的临时对象。

但是我对如何重新初始化对象感到困惑,因为:

o.Object(arg)

不允许。

我可以创建一个名为 init(arg) 的方法并调用

o.init(arg)

这与 Object::Object(arg) 执行相同的初始化,但我不希望创建一个额外的方法,该方法具有我需要记住的“非标准”名称。

有没有办法调用已经创建的对象的构造函数来重新初始化它而不进行复制?

【问题讨论】:

  • “这会在堆栈中创建一个新对象,然后将其复制到对象 o 并在之后将其删除。” - 仅当您的编译器运行良好且真正完全愚蠢时.. ..啊,我看到你编译时没有优化...
  • 你的类是否支持 move 语义或者它是否有 swap(...) 函数?
  • 如果您将对象定义为Object o;,那么只需 assign 给它以再次“初始化”它吗?如o = Object();.
  • 出于好奇,为什么需要再次“初始化”它?
  • @StoryTeller 因为我正在为嵌入式编程,所以我更喜欢控制内存,并且我将所有“大”事物的变量放在任何函数之外,以便在编译时分配它们,我知道它们合身。我喜欢在 init 函数中初始化它们,因为我认为代码更整洁一些。在某些情况下,如果我让处理器进入睡眠状态,并且某些硬件和软件都需要重新初始化,可能还需要重新初始化对象。

标签: c++ stack


【解决方案1】:

考虑在对象的当前内存上使用新位置。这将在当前使用的内存中初始化一个新对象,而不分配新内存。这可能是您的解决方案。例如:

new (&o) Object(args)

试试这个:

#include <iostream>

class A
{
public:

    A(int i)
    {
        m_i = i;
    }

    int m_i;
};

int main()
{
    int s = 10;
    int *ps = new (&s) int(100);
    std::cout << *ps;
    std::cout << s;

    A a(5);
    new (&a) A(49);
    std::cout << a.m_i;
}

g++ -std=c++98 main.cpp 返回 10010049,这是正确的。

【讨论】:

【解决方案2】:

您需要使用placement new 并调用下面的对象析构函数示例

A a = A();//init
a.~A();//clear
new (&a) A();//re init

【讨论】:

  • 那个代码是UB,如果你首先使用了placement new,你只能显式删除。
  • @john 不,不是,你在哪里见过?
  • 请注意,如果A 的构造函数可以抛出异常,此方法可能需要捕获异常。否则,将为尚未构造的对象(即 UB)调用析构函数。
  • @DanielLangr 我将假设此示例 A() 将成功构建类
  • @DanielLangr - 考虑到 OP 多次强调“嵌入”,我怀疑可能有例外。
【解决方案3】:

步骤 1. 获得一个可以工作的编译器(即识别最明显的初始化对象的机会)并且至少支持 C++11。

第 2 步。用于初始化:

auto o = Object(arg); // won't copy ever with optimization turned on

如果您需要为构造函数重新分配新参数:

o = Object(arg1); // calls move asignment operator

如果您需要用不同对象的值覆盖该值(以后不打算使用:

o = std::move(o1); // o1 is the other Object, afterwards o1 is left in 'valid but undefinded state'

如果这对您不起作用(仍然是堆栈颠簸/无移动赋值运算符等),您可能应该选择放置 new,像 @tomer zeitune 建议的那样显式调用析构函数:

o.~Object(); // cleanup
new (&o) Object();

需要显式调用析构函数,例如释放对象管理的所有资源。

【讨论】:

  • 我们不知道没有定义提供的任意“对象”是否有任何移动赋值运算符。
  • 当我打开 O3 级别的优化时,编译器仍会将对象放在堆栈中以便稍后移动它。不幸的是,我似乎无法使用o = Object(arg1);
猜你喜欢
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-12
  • 1970-01-01
  • 2012-01-02
  • 2011-10-15
相关资源
最近更新 更多