【问题标题】:Compiling C++ without the delete operator不使用删除运算符编译 C++
【发布时间】:2016-12-29 07:31:44
【问题描述】:

我正在为嵌入式设备编写一个 C++ 程序,我想在没有 libstdc++、异常和动态内存分配的情况下编译它。

示例程序:

#include <stdio.h>

class A
{
public:
    virtual ~A() {}
    virtual void Foo() = 0;
};

class B : public A
{
public:
    virtual ~B() {}
    virtual void Foo() override{}
};

int main()
{
    B b;
    return 0;
}

我立即遇到了以下错误。

$ gcc src.cpp -static -fno-rtti -fno-exceptions -std=c++11

/tmp/ccd0Wydq.o: 在函数中A::~A()': src.cpp:(.text._ZN1AD2Ev[_ZN1AD5Ev]+0x29): undefined reference to operator delete(void*)' /tmp/ccd0Wydq.o: 在函数中A::~A()': src.cpp:(.text._ZN1AD0Ev[_ZN1AD5Ev]+0x20): undefined reference to operator delete(void*)' /tmp/ccd0Wydq.o: 在函数中B::~B()': src.cpp:(.text._ZN1BD2Ev[_ZN1BD5Ev]+0x35): undefined reference to operator delete(void*)' /tmp/ccd0Wydq.o: 在函数B::~B()': src.cpp:(.text._ZN1BD0Ev[_ZN1BD5Ev]+0x20): undefined reference to operator delete(void*)' /tmp/ccd0Wydq.o:(.rodata._ZTV1A[_ZTV1A]+0x20): 未定义的引用 `__cxa_pure_virtual' collect2:错误:ld 返回 1 退出状态 Makefile:2: 目标“all”的配方失败 make: *** [all] 错误 1

我明白为什么需要__cxa_pure_virtual,但我一生都无法理解为什么需要delete 实现。

我没有在代码中执行newdelete 操作,为什么需要它?

当实现这两个函数以满足链接器的需求时,似乎都没有调用(如预期的那样)。

有没有办法避免实现这些功能?

【问题讨论】:

  • 让它们什么都不做来实现它们有什么问题吗?
  • 我会用一个大的assert(1==0) 对它们进行存根,以确保它们不会被调用。
  • 这是一个丑陋的解决方案。如果这是唯一的解决方案,我会这样做,但我想知道为什么会这样。
  • 尝试添加-flto-fwhole-program-Wl,--as-needed

标签: c++ linker delete-operator


【解决方案1】:

当通过delete 表达式调用虚拟析构函数时,被调用的operator delete 由最派生类的范围确定。例如,

#include <iostream>

class Base {
public:
    virtual ~Base() {}
};

void destroy_base(Base* b) { delete b; }

class Derived : public Base {
public:
    static void operator delete(void* ptr) {
        std::cout << "Derived::operator delete\n";
        ::operator delete(ptr);
    }
};

int main() {
    destroy_base( new Derived );
}

打印"Derived::operator delete",即使函数destroy_base不知道类Derived

g++ 通过在每个类的 vtable 中放置两个版本的析构函数来实现这一点:一个只销毁成员和基,另一个完成所有这些然后调用适当的operator delete。这是您未定义符号的来源。

如果您从未真正使用过delete 表达式,只需将::operator delete 函数存根就可以了。

【讨论】:

  • 有没有办法阻止编译器生成第二个析构函数?我对删除删除操作符不感兴趣。
  • 我不这么认为。
  • @GiladNaaman,无法想象这怎么可能。标准要求调用正确的 delete,并且在编译基类时,编译器不知道它会如何使用 - 所以它必须生成调用 operator delete 的析构函数。
  • 谢谢你的澄清,我会按照建议写一个存根。
猜你喜欢
  • 2014-05-24
  • 1970-01-01
  • 2012-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-28
  • 2014-04-24
  • 2012-12-03
相关资源
最近更新 更多