2016-08-22 37 views
10

Piszę program C++ dla urządzenia osadzonego i chcę skompilować go bez libstdC++, wyjątków i dynamicznej alokacji pamięci.Kompilowanie C++ bez operatora usuwania

Przykładowy program:

#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; 
} 

natychmiast uruchomiony do następujących błędów.

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

/tmp/ccd0Wydq.o: In function A::~A()': src.cpp:(.text._ZN1AD2Ev[_ZN1AD5Ev]+0x29): undefined reference to operator delete(void*)' /tmp/ccd0Wydq.o: In function A::~A()': src.cpp:(.text._ZN1AD0Ev[_ZN1AD5Ev]+0x20): undefined reference to operator delete(void*)' /tmp/ccd0Wydq.o: In function B::~B()': src.cpp:(.text._ZN1BD2Ev[_ZN1BD5Ev]+0x35): undefined reference to operator delete(void*)' /tmp/ccd0Wydq.o: In function B::~B()': src.cpp:(.text._ZN1BD0Ev[_ZN1BD5Ev]+0x20): undefined reference to operator delete(void*)' /tmp/ccd0Wydq.o:(.rodata._ZTV1A[_ZTV1A]+0x20): undefined reference to `__cxa_pure_virtual' collect2: error: ld returned 1 exit status Makefile:2: recipe for target 'all' failed make: *** [all] Error 1

rozumiem dlaczego __cxa_pure_virtual jest potrzebna, ale nie mógł do życia mnie dostać dlaczego muszę realizację delete.

Nie wykonuję w kodzie operacji new ani delete, dlaczego byłaby potrzebna?

Podczas implementowania obu funkcji w celu spełnienia żądań łącznika, wydaje się, że żadne z nich nie jest wywoływane (zgodnie z oczekiwaniami).

Czy istnieje sposób na uniknięcie wdrożenia tych funkcji?

+0

Czy jest coś złego w ich wdrażaniu, ponieważ nie robią nic? –

+0

Wstawię je przy dużym "assert (1 == 0)", aby upewnić się, że nie są wywoływane. –

+0

To brzydkie rozwiązanie. Zrobię to, jeśli to jedyne rozwiązanie, ale chcę wiedzieć, dlaczego tak jest. –

Odpowiedz

12

Po wywołaniu wirtualnego destruktora przez wyrażenie delete, wywoływane operator delete jest określane na podstawie zakresu najbardziej pochodnej klasy. Na przykład,

#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); 
} 

drukuje "Derived::operator delete", chociaż funkcja destroy_base ma wiedzę o klasie Derived.

g ++ implementuje to poprzez umieszczenie dwóch wersji destruktora w vtable każdej klasy: takiej, która po prostu niszczy elementy i podstawy, i która wykonuje to wszystko, a następnie wywołuje odpowiednią operator delete. Tu pochodzą twoje niezdefiniowane symbole.

Jeśli nigdy nie używasz wyrażenia delete, po prostu odłącz funkcję ::operator delete i powinieneś być w porządku.

+0

Czy istnieje sposób, aby uniemożliwić kompilatorowi generowanie drugiego destruktora? Nie jestem zainteresowany zatkaniem operatora delete. –

+0

Nie wierzę w to. – aschepler

+1

@GiladNaaman, nie mogę sobie wyobrazić, jak to byłoby możliwe. Standard wymaga wywołania odpowiedniego usunięcia, a podczas kompilowania klasy bazowej kompilator nie ma pojęcia, w jaki sposób zostanie użyty - więc musi wygenerować destruktor, który wywołuje operację delete. – SergeyA