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