Skip to content

Commit

Permalink
C++ lifetime function handling documentation
Browse files Browse the repository at this point in the history
calling C++ constructors in D are now possible and so must be updated in documentation
  • Loading branch information
Emmanuel Nyarko authored and Emmanuel Nyarko committed Apr 4, 2024
1 parent c53262f commit bab50f7
Showing 1 changed file with 113 additions and 11 deletions.
124 changes: 113 additions & 11 deletions spec/cpp_interface.dd
Original file line number Diff line number Diff line change
Expand Up @@ -933,17 +933,119 @@ $(H2 $(LNAME2 packing-and-alignment, Packing and Alignment))

$(H2 $(LNAME2 lifetime-management, Lifetime Management))

$(P C++ constructors, copy constructors, move constructors and destructors
cannot be called directly in D code, and D constructors, postblit operators
and destructors cannot be directly exported to C++ code. Interoperation of
types with these special operators is possible by either 1$(RPAREN)
disabling the operator in the client language and only using it in the host
language, or 2$(RPAREN) faithfully reimplementing the operator in the
client language. With the latter approach, care needs to be taken to ensure
observable semantics remain the same with both implementations, which can be
difficult, or in some edge cases impossible, due to differences in how the
operators work in the two languages. For example, in D all objects are
movable and there is no move constructor.)
$(P C++ constructors, copy constructors, and destructors can be called directly in D code.
C++ move constructors cannot be called directly in D code.
)

$(P In a foo.cpp file: )

$(CPPLISTING
#include $(LT)iostream$(GT)

using namespace std;

class A
{
public:
A(int i);
~A();
};

A::A(int i)
{
cout << "calling C++ integer constructor " << endl;
}

A::~A()
{
cout << "calling C++ destructor " << endl;
}
)

$(P In a bar.d file: )

------
extern(C++) class A
{
this(int i);
~this();
}

void main()
{
auto obj1 = new A(5); // calls the constructor
destroy!false(obj1); //calls the destructor
}
------

$(P Compiling, linking, and running produces the output:)

$(CONSOLE
$(GT) g++ -c foo.cpp
$(GT) dmd bar.d foo.o -L-lstdc++ && ./bar
calling C++ integer constructor
calling C++ destructor
)

$(P Note that you cannot call C++ Copy constructor using D classes since classes in D are reference types.
you need value semantics to be able to copy so you need to call them using D struct.)

$(P In a foo.cpp file: )

$(CPPLISTING
#include $(LT)iostream$(GT)

using namespace std;

class A
{
public:
A(int i);
A(A const& other);
~A();
};

A::A(int i)
{
cout << "calling C++ integer constructor" << endl;
}

A::A(A const& other)
{
cout << "calling C++ copy constructor" << endl;
}
)

$(P In a bar.d file: )

------
extern(C++, class) struct A
{
this(int i);
this(ref const A other);
~this();
}

void main()
{
A obj1 = 6; // calls the integer constructor
auto obj2 = A(obj1); // calls the copy constructor
}
------

$(P Compiling, linking, and running produces the output:)

$(CONSOLE
$(GT) g++ -c foo.cpp
$(GT) dmd bar.d foo.o -L-lstdc++ && ./bar
calling C++ integer constructor
calling C++ copy constructor
calling C++ destructor
calling C++ destructor
)

$(P Notice you don't need to call destroy on a struct object to invoke the destructor
since it does stack allocation and its lifetimes ends after leaving the stack.)

$(H2 $(LNAME2 special-member-functions, Special Member Functions))

Expand Down

0 comments on commit bab50f7

Please sign in to comment.