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



# 😖

Reply via email to