www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - extern(C++): Unresolved scalar deleting destructor

reply Vladimir Marchevsky <vladimmi gmail.com> writes:
After reading 2.081 patchnotes about improvements with binding to 
cpp classes, I'm trying to test it - with simple examples and Qt 
as cpp library.

My naive approach is to bind just a couple of used methods of 
specific classes (omitting others) and try to use it directly in 
D just with linking of default Qt5Core.lib. Sometimes it works 
just fine:

---app.d
import std.conv;
import std.stdio;

extern(C++) {
     class QVariant {
         this();
         this(int);
         this(double);
         final ~this();

         final int toInt(bool *ok = null) const;
         final double toDouble(bool *ok = null) const;
     }
}

void main()
{
     QVariant a = new QVariant(5);
     QVariant b = new QVariant(5.5);
     writeln("a: " ~ a.toInt().to!string);
     writeln("b: " ~ b.toDouble().to!string);
     readln();
}
---

This example compiles and works like a charm.

Other classes like QObject or QCoreApplication do not link with 
error like this:

cpptest.obj : error LNK2001: unresolved external symbol ""public: 
virtual void * __cdecl QObject::`scalar deleting 
destructor'(unsigned int)" (??_GQObject  UEAAPEAXI Z)"

There is no such symbol in Qt5Core.lib, obviously. Is it my 
mistake somewhere? Why do some classes require this destructor 
when it doesnt actually exist in lib? And why do other classes 
work without it?
Jul 24 2018
next sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Tuesday, 24 July 2018 at 15:48:28 UTC, Vladimir Marchevsky 
wrote:
 After reading 2.081 patchnotes about improvements with binding 
 to cpp classes, I'm trying to test it - with simple examples 
 and Qt as cpp library.

 My naive approach is to bind just a couple of used methods of 
 specific classes (omitting others) and try to use it directly 
 in D just with linking of default Qt5Core.lib. Sometimes it 
 works just fine:

 ---app.d
 import std.conv;
 import std.stdio;

 extern(C++) {
     class QVariant {
         this();
         this(int);
         this(double);
         final ~this();

         final int toInt(bool *ok = null) const;
         final double toDouble(bool *ok = null) const;
     }
 }

 void main()
 {
     QVariant a = new QVariant(5);
     QVariant b = new QVariant(5.5);
     writeln("a: " ~ a.toInt().to!string);
     writeln("b: " ~ b.toDouble().to!string);
     readln();
 }
 ---

 This example compiles and works like a charm.

 Other classes like QObject or QCoreApplication do not link with 
 error like this:

 cpptest.obj : error LNK2001: unresolved external symbol 
 ""public: virtual void * __cdecl QObject::`scalar deleting 
 destructor'(unsigned int)" (??_GQObject  UEAAPEAXI Z)"

 There is no such symbol in Qt5Core.lib, obviously. Is it my 
 mistake somewhere? Why do some classes require this destructor 
 when it doesnt actually exist in lib? And why do other classes 
 work without it?
Seems like it's virtual destructor could that be? this qt5 binding: https://github.com/MGWL/QtE5/blob/master/source/qte5.d seems to always define the constructor.
Jul 24 2018
parent Vladimir Marchevsky <vladimmi gmail.com> writes:
On Tuesday, 24 July 2018 at 16:30:41 UTC, Stefan Koch wrote:
 Seems like it's virtual destructor could that be?

 this qt5 binding: 
 https://github.com/MGWL/QtE5/blob/master/source/qte5.d
 seems to always define the constructor.
No, simple virtual (or final) destructor binds just fine with "~this()" or "final ~this()". "Scalar deleting destructor" is special thing, afaik, and my C++ knowledge is not enough to determine why is it required by D side and not required in C++ or not available in compiled lib. QtE5, DQml or similar projects mostly wrap cpp-objects - create them on cpp side with helper function, save returned pointer on d side and operate via wrapper-functions that call methods on cpp side. But it looks I should be mostly able to interact with cpp-defined classes directly now, from 2.081 patchnotes: "This release also includes ABI fixes where destructors are now correctly added to the virtual table, and constructor/destructor calling semantics now match C++. With this, mixed-language class hierarchies are working, with construction/destruction being supported in either language."
Jul 24 2018
prev sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 24 July 2018 at 15:48:28 UTC, Vladimir Marchevsky 
wrote:
 After reading 2.081 patchnotes about improvements with binding 
 to cpp classes, I'm trying to test it - with simple examples 
 and Qt as cpp library.

 [...]
Have you tried disable ~this()? Alexander
Jul 24 2018
parent reply Vladimir Marchevsky <vladimmi gmail.com> writes:
On Tuesday, 24 July 2018 at 19:04:50 UTC, 12345swordy wrote:
 Have you tried  disable ~this()?
Just tried: 1) no changes, still error about unresolved "QObject::`scalar deleting destructor'(unsigned int)". 2) marking destructor as disable will actually disable it, right? But I want to use to not receive a memory leak. Afaik, previous approach was to re-implement ctor/dtor in D but now they can be used as they are.
Jul 24 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 24 July 2018 at 19:14:26 UTC, Vladimir Marchevsky 
wrote:
 On Tuesday, 24 July 2018 at 19:04:50 UTC, 12345swordy wrote:
 Have you tried  disable ~this()?
Just tried: 1) no changes, still error about unresolved "QObject::`scalar deleting destructor'(unsigned int)". 2) marking destructor as disable will actually disable it, right? But I want to use to not receive a memory leak. Afaik, previous approach was to re-implement ctor/dtor in D but now they can be used as they are.
I found similar error messages regarding c++: https://stackoverflow.com/questions/42449063/vs-c-dll-scalar-deleteing-destructor
Jul 24 2018
parent reply Vladimir Marchevsky <vladimmi gmail.com> writes:
On Tuesday, 24 July 2018 at 19:30:49 UTC, 12345swordy wrote:
 I found similar error messages regarding c++:
 https://stackoverflow.com/questions/42449063/vs-c-dll-scalar-deleteing-destructor
Hmm, so looks like it's really because of virtual destructor, like Stefan mentioned before. Implementing empty destructor in D removes error. Gonna check what C++ does in similar case and any possible problems... Thanks to everyone for pointing out the direction to dig :)
Jul 24 2018
parent reply Vladimir Marchevsky <vladimmi gmail.com> writes:
Back to questions after homework done :) What I've tested:

Made test class in CPP:

---testlib.cpp
class __declspec(dllexport) Foo {
     int *a;

public:
     Foo(int value) {
         a = new int(value);
     }

     ~Foo() {
         delete a;
     }
};
---

Binding on D side:

---
extern(C++) {
     class Foo {
         this(int value);
         final ~this();    //btw, is this a correct way to bind a 
non-virtual member?
                           //What about inheritance and so on?..
     }
}
---

Binding works perfect, both ctor and dtor work.

Changed dtor to be virtual (and removed final from D side) - 
anyway, compiles and works perfect. I can provide D 
implementation of destructor which replaces original virtual one 
(is it correct? Or can I call original one from D-specified?) - 
making it empty leads to memory leak as expected. So I see no 
problems here.

Back to QObject. Its destructor is "virtual ~QObject();" but 
having "~this();" on D side again leads to "unresolved scalar 
deleting destructor" of QObject. It looks like actual destructor 
binds correct (I would have another error if I make binding 
incorrect with "final ~this()") but for some reason it wants this 
another thing... Why?
Jul 25 2018
parent Vladimir Marchevsky <vladimmi gmail.com> writes:
On Wednesday, 25 July 2018 at 12:04:16 UTC, Vladimir Marchevsky 
wrote:
 What I've tested:
Even more: if I create another trivial class in cpp (say, Bar) and new/delete it in first one ("b = new Bar();" in ctor, "delete b;" in dtor of Foo) - D app with bound Foo just crashes silently for some reason.
Jul 25 2018