Create objects in conditional c++ statements

前端 未结 7 1289
悲哀的现实
悲哀的现实 2020-12-06 01:33

I am learning c++, and I just got to the object oriented chapter. I have a question about creating objects inside if statements.

The problem I\'m working on says

7条回答
  •  夕颜
    夕颜 (楼主)
    2020-12-06 01:53

    As of C++17, you can now use std::optional for this task - it avoids dynamic memory allocation, it avoids two-phase construction of the object, and it doesn't require the type to be movable or copyable. It allows you to delay the construction of the object while keeping it on the stack and also still being exception-safe. If you construct it in every branch you can safely use it afterward with no performance penalty. It will also work as a class member allowing you to avoid the problem with the class constructor initializer for it, unlike the rvalue reference solution. Demo: https://gcc.godbolt.org/z/vbe5eh

    #include 
    
    struct UseCtorA final {};
    struct UseCtorB final {};
    struct Report final
    {
        Report() = delete;
        Report(Report const &) = delete;
        Report(Report &&) = delete;
        Report &operator=(Report const &) = delete;
        Report &operator=(Report &&) = delete;
    
        Report(UseCtorA, char c) : v{1} { if(c == 't'){ throw 3; } }
        Report(UseCtorB) : v{2} {}
    
        constexpr auto getValue() const noexcept { return v; }
    
    private:
        int v;
    };
    
    int main(int nargs, char const *const *args)
    {
        std::optional report;
        if(nargs > 2)
        {
            report.emplace(UseCtorA{}, args[1][0]);
        }
        else
        {
            report.emplace(UseCtorB{});
        }
        return report->getValue();
    }
    

    If you are stuck in an older compiler that only supports C++11, you can make your own really dumb version of std::optional for this express purpose by using a union and placement new:

    struct Empty final {};
    template
    struct Optional
    {
        Optional() noexcept : unused{} {}
        ~Optional() noexcept(noexcept(v.~T()))
        {
            if(constructed_successfully)
            {
                v.~T();
            }
        }
        template
        auto emplace(Args &&... args) -> T &
        {
            if(constructed_successfully)
            {
                v.~T();
                constructed_successfully = false;
            }
            T &r = *new (&v) T(std::forward(args)...);
            constructed_successfully = true;
            return r;
        }
        auto operator->() noexcept -> T *
        {
            return &v;
        }
    
    private:
        union
        {
            T v;
            [[no_unique_address]] Empty unused;
        };
        bool constructed_successfully = false;
    };
    

    The generated assembly is identical to with std::optional: https://gcc.godbolt.org/z/vzGz9E

    Though, I would recommend using an existing library to supplement your lack of access to std::optional instead of rolling your own like I have done above - my version doesn't work for copying or moving.

提交回复
热议问题