What's the correct way of creating an instance of class in D?

Tejas notrealemail at gmail.com
Thu Nov 3 13:31:35 UTC 2022


On Thursday, 3 November 2022 at 04:41:14 UTC, Siarhei Siamashka 
wrote:
> C++ code:
> ```C++
> #include <iostream>
> class A {
> public:
>   void foo() { std::cout << "foo" << std::endl; }
> };
> int main() {
>   auto a1 = new A;
>   a1->foo(); // prints "foo"
>   A a2;
>   a2.foo();  // prints "foo"
>   delete a1;
> }
> ```
> D code:
> ```D
> @safe:
> import std.stdio;
> class A {
>   void foo() { writeln("foo"); }
> }
> void main() {
>   auto a1 = new A;
>   a1.foo(); // prints "foo"
>   A a2;
>   a2.foo(); // Segmentation fault
> }
> ```
>
> I didn't expect to see a segmentation fault in the code, which 
> is a straightforward conversion from C++. And especially not 
> with the use of the `@safe` attribute. What's going on here?
>
> ```
> $ ldc2 --version
> LDC - the LLVM D compiler (1.30.0):
>   based on DMD v2.100.1 and LLVM 14.0.6
>   built with LDC - the LLVM D compiler (1.30.0)
>   Default target: x86_64-pc-linux-gnu
> ```

In D, all references and pointer types are default initialized to 
`null` no matter what, so you always have to explicitly assign an 
initial value if you dont want segfaults when dereferencing them

```d
import std.stdio:writeln;


void main(){
     int* a;
     writeln(*a); // program killed by signal 11
     int* b = new int();
     writeln(*b);
}
```

C++ initializes variable via the default constructor though, 
because it is a value type, like D's `struct`s

```cpp
#include <iostream>

using namespace std;


class A{
     public:
     A(){
         this -> a = new int(44);
     }
     int* a;
};

int main()
{
     int* a;

     cout << *a << "\n"; //prints any garbage value

     A instance;
     cout << *instance.a  << "\n"; // always prints 44
     return 0;
}
```

Use a pointer, and you'll get the same undesirable behaviour

```cpp
#include <iostream>

using namespace std;


class A{
     public:
     A(){
         this -> a = new int(44);
     }
     int* a;
};

int main()
{
     int* a;

     cout << *a << "\n"; //prints any garbage value

     A* instance;
     cout << instance ->a  << "\n"; // it's printing nothing for 
some reason
     return 0;
}
```

You do get an error message if you use reference though, which D 
doesn't give even when using `@safe`

C++:
```cpp
#include <iostream>

using namespace std;


class A{
     public:
     A(){
         this -> a = new int(44);
     }
     int* a;
};

int main()
{
     int* a;

     cout << *a << "\n"; //prints any garbage value

     A& instance;
     cout << instance.a  << "\n"; // it's printing nothing for 
some reason
     return 0;
}

main.cpp: In function ‘int main()’:
main.cpp:28:8: error: ‘instance’ declared as reference but not 
initialized
    28 |     A& instance;
       |        ^~~~~~~~

```

D with `@safe`:

```d
import std.stdio:writeln;


void main() @safe {
     int* a;
     writeln(*a); // still segfault
     int* b = new int();
     writeln(*b);
}
```



# 😖


More information about the Digitalmars-d-learn mailing list