C++ Weekly - Ep 154 - One Simple Trick For Reducing Code Bloat

preview_player
Показать описание
☟☟ Awesome T-Shirts! Sponsors! Books! ☟☟

T-SHIRTS AVAILABLE!

WANT MORE JASON?

SUPPORT THE CHANNEL

GET INVOLVED

JASON'S BOOKS

► C++23 Best Practices

► C++ Best Practices

JASON'S PUZZLE BOOKS

► Object Lifetime Puzzlers Book 1

► Object Lifetime Puzzlers Book 2

► Object Lifetime Puzzlers Book 3

► Copy and Reference Puzzlers Book 1

► Copy and Reference Puzzlers Book 2

► Copy and Reference Puzzlers Book 3

► OpCode Puzzlers Book 1


RECOMMENDED BOOKS

AWESOME PROJECTS

O'Reilly VIDEOS

Рекомендации по теме
Комментарии
Автор

It's 9 months since this video was posted and I just tried the different examples using Compiler Explorer. The results were quite different from what was shown here. Generally, x-84-64 gcc (trunk) was much better that clang trunk at optimizing the code in all cases. Declaring a destructor added 3 instructions vs. not declaring one (26 vs 29. For x86-64 clang (trunk), declaring a destructor actually reduced code by 7 instructions vs not declaring one (83 vs 90). This is with using std::string and two emplace_back calls. With the destructor also defined, gcc produces 40 lines vs clang's 106.

Declaring or not declaring a destructor had varying impacts, depending on the data types being used. For int, gcc generated 10 lines fewer with a destructor declared vs not (26 vs 36). Clang is the other way around. W/o a destructor declared, it generates 28 lines. With it declared, it generates 71 lines.

It's difficult to make a pat rule about whether or not to declare a destructor. Thus far, though, also defining one will add extra instructions. But the choice of compiler seems to be far more important than the declare/don't declare of the destructor.

BTW, ~S() = default produces the same instruction count as not declaring ~S() at all.

risajajr
Автор

Funny where I used to work all the cpp gurus demanded all objects have destructors regardless of use

mikecmw
Автор

Visual Studio, when adding a new class, automatically creates an empty constructor and destructor in the .cpp file and I might sometimes forget to delete it. Thanks for the tip.

xonxt
Автор

wow.. i actually tried this on our company's codebase a few weeks ago. It really really made a difference in the size of executable. Very true.

hopefulrational
Автор

About 7:14, aren't destructors already implicitly noexcept?

SrIgort
Автор

6:35 I've seen this exact pattern in a code written by someone who claimed that compiler can't be as fast with "smart" pointer as with raw pointer. He implemented the "smart" himself, of course, and added the nulling in the d-tor. ;-) Why???///

michal.gawron
Автор

Thanks for the video! I'm wondering why there is a difference in generated code between having no constructor, and having a constructor declared as `~S() = default;`. Shouldn't these cases be more or less equivalent?

kmhofmann
Автор

What if you use =default for the destructor?

JohnDlugosz
Автор

With -O2 optimization

struct S {
std::string s;
};

and

struct S {
std::string s;
~S() {}
};

do exactly the same thing and lead to exactly the same object code. It's possible that with no optimization or a bad compiler the one with the explicit destructor takes more microprocessor instructions, but any decent compiler can figure out the two versions are identical.

real
Автор

But what about having default move ctor and move assign? Then it's all movable again and then it shouldn't be a problem? Or is that still a problem? I make a habbit of providing at least 1 ctor (could be default), copy +move ctor (default or delete), copy+move operator (default or delete) and 1 dtor (pretty much always default)... Would I still run into this? Because if I allow for default move it should be able to figure this out right?

ruadeil_zabelin
Автор

so base on the example; this doesnt take account cases of virtual destructors and heritance. right ?

BloodHaZaRd
Автор

Dude, if I had a penny every time I pointed this out in a code review...

KobiCohenArazi
Автор

That Heap Allocation eLlision Optimization (HALO) is really nice in situations like this. It's something I hope the gcc devs give serious consideration to.

timhaines
Автор

Is there a way to omit the empty destructor in case of polymorphic objects? Perhaps I'm not remembering it right, but if I do so I remember that I always had to explicitly declare a virtual destructor, even if it was empty.
PS: Aren't destructors noexcept by default?

theIpatix
Автор

I have plenty of empty destructors! Lol

theugobosschannel
Автор

GCC seems to be optimizing for speed, clang looks like optimizing for size. Have you tried to use -Os for GCC?

ernestuz
Автор

dtors are always noexcept unless you make them noexcept(false) or the implicitly generated one is noexcept. Hense why I assume dtors are always noexcept

connorhorman
Автор

Just what I think of when someone says "code bloat". Some generated compiler assembly from destructors /s

losthighway
Автор

Am I defining a destructor when I do ~ClassName() = default; ?

multiHappyHacker
Автор

I haven't watched it yet but the title caught my eye. I need a welcome break from debugging a compile error in a generic lambda passed to std::visit inside a SFINAE'd template function inside a templated class.

jonesconrad