0

I've got this piece of code:

class BuffComponent : public Component
{

public:
    using BuffMap =
        std::unordered_map<Effect, std::unique_ptr<EffectComponent>>;
    BuffMap buffs;

    BuffComponent() {}

    BuffComponent(const BuffComponent &buff_component)
    {
        for (auto &buff : buff_component.buffs)
        {
            this->buffs[buff.first] =
                std::unique_ptr<EffectComponent>(buff.second->clone());
        }
    }

    BuffComponent(std::initializer_list<EffectComponent *> buffs_list)
    {
        for (auto &buff : buffs_list)
        {
            buffs[(buff->effect & ~(APPLIED | APPLY_ONCE))] =
                std::unique_ptr<EffectComponent>(buff);
        }
    }

    BuffComponent *clone() const override { return new BuffComponent(*this); }
};

Which compiles perfectly fine. My main looks like this (for testing)

int main()
{
    std::cout << "I HAVEN'T CRASHED!";
    std::unique_ptr<BuffComponent>  i(new BuffComponent());
}

The base Component class looks like this:

class Component
{

public:
    virtual Component *clone() const = 0;
    virtual ~Component() {}
};

The problem I'm experiencing is that for whatever reason, the program crashes and doesn't display the "I HAVEN'T CRASHED!". I can't even seem to debug it with gdb, as it immediately quits with an exit code 139 (which I found has something to do with memory). My question is, what is wrong about my understanding? I can't see anything obvious that would cause this to compile but fail at runtime.

When the lines responsible for map acccess are commented inside the for each loop, the program does not crash and functions correctly. This leads me to believe that accessing the map violates the memory somehow, but I don't understand why. I'd really appreciate any help, it's been driving me nuts

aallfik11
  • 59
  • 5
  • 3
    Somewhere in the code not shown, you have a global variable of class type, and the constructor of that class crashes. Possibly due to the [Static Initialization Order Fiasco](https://en.cppreference.com/w/cpp/language/siof) whereby one global variable depends on another, but is initialized before that other variable. – Igor Tandetnik Apr 23 '23 at 23:12
  • 1
    Firstly, whenever you encounter a "weird" behavior of any sense in C++, it's most likely [undefined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) which can cause _anything_. Do you assume you can reason about the behavior of an incorrect program. Secondly, either use `cerr` instead of `cout` for debugging or flush the buffer after each debug print (`<< std::endl` or `cout.flush()`). – yeputons Apr 23 '23 at 23:14
  • @IgorTandetnik if that were the case, why does commenting the piece `this->buffs[buff.first] = std::unique_ptr(buff.second->clone());`make it not crash? I'm not even calling that constructor in any global place – aallfik11 Apr 23 '23 at 23:17
  • 1
    @aallfik11 *if that were the case, why does...* -- No. Once a program corrupts memory, then anywhere in the program can show signs of corruption. I suggest you put the code back to where it crashes all the time, and fix the problem starting from there. – PaulMcKenzie Apr 23 '23 at 23:20
  • @PaulMcKenzie Is there any way to look for that? Like a tool or something? It also worked fine when everything was (incorrectly, as it obviously was a bad design which I learned later) made using shared_ptrs instead of unique_ptrs – aallfik11 Apr 23 '23 at 23:24
  • 1
    Nothing obvious in the code shown. This needs a [example]. Good luck without one, because there's nothing we can do otherwise. – JohnFilleau Apr 23 '23 at 23:25
  • 2
    @aallfik11 Compile and run your program with ASAN and UBsan: `-fsanitize=address,undefined`. It you have multithreading also compile and run it separately with `-fsanitize=thread`. As the first comment mentioned, the problem is likely in dynamic initialization of a non-local static storage duration variable if you can't reach `main` in the debugger. (It is really easy to cause undefined behavior by having such variables depend on one another in their initialization, which is why they should be avoided as much as possible.) – user17732522 Apr 23 '23 at 23:25
  • 2
    If a program contains [UB](https://en.cppreference.com/w/cpp/language/ub) *anywhere* then the *entire program* is undefined/invalid and the compiler is under no obligation to do anything sensible *anywhere*. UB in one place can lead to otherwise correct code elsewhere doing weird things. – Jesper Juhl Apr 23 '23 at 23:26
  • Thank you for your comments, I'll try to use the sanitizer, maybe try valgrind (dunno how to use it yet) and report back in a few hours. – aallfik11 Apr 23 '23 at 23:29
  • 3
    Raymond Chen has a good blog post about UB causing "time travel" among other things. https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633 – JohnFilleau Apr 23 '23 at 23:31
  • 4
    @aallfik11 *Which compiles perfectly fine* -- [Are you sure about that?](https://godbolt.org/z/dGcvxK65c) – PaulMcKenzie Apr 23 '23 at 23:34
  • "why does commenting the piece ... make it not crash?" At the very least, this means *something* actually calls this piece of code. But nothing in the code shown does. Ergo, the problem must needs lie somewhere in the code not shown. E.g. you might be copying a `BuffComponent` instance that wasn't in fact initialized. – Igor Tandetnik Apr 24 '23 at 00:19
  • Unrelated to your problem (but it could be related indeed) - your function should never return a raw pointer to an owned object, return a smart pointer instead. And use `std::make_unqiue` or `std::make_shared` – Slava Apr 24 '23 at 01:31
  • A minimal reproducible sample is required. Looks like you are posting the less relevant part of code. – Red.Wave Apr 24 '23 at 05:27
  • `std::cout << "I HAVEN'T CRASHED!";` You forgot to flush the stream. This will make it lose data in case of a crash. `<< std::endl` should do the job. – n. m. could be an AI Apr 24 '23 at 07:50
  • @n.m. the problem is that as of right now, my program seems to crash before even reaching main. – aallfik11 Apr 24 '23 at 08:12
  • "seems to crash" You don't know whether it crashes before `main`. You add a *useless* unflushed `cout<<` to `main`. Guess what? You still don't know whether it crashes before `main`. How about adding a useful `cout<<` that will provide some positive indication? – n. m. could be an AI Apr 24 '23 at 08:20
  • It seems my problems might not actually be caused by any part of my program, instead it's that vscode and cmaketools behave in a weird way. When I run the compiled executable directly from the commandline, it prints the messages just fine and doesn't give me any errors. I tested the code here and it works fine as well https://godbolt.org/z/YGcoqEhMY – aallfik11 Apr 24 '23 at 10:17

0 Answers0