3

I've put a custom class Unit in an std::atomic. Class looked as follows with a default constructor

namespace Base
{
    template <typename T, typename R, typename D>
    class Unit
    {
    public: 
        constexpr Unit() = default;
    private:
        T m_Value;
    };
}

It used to work fine until I noticed I forgot to initialize the only member of my class to zero in the default constructor. Therefore I removed the = default and provided an implementation of the constructor

template <typename T, typename R, typename D>
constexpr Unit<T, R, D>::Unit() :
    m_Value(T(0))
{   }

Now I am getting a compiler error:

Error C2280 'std::atomic<Base::Unit>::atomic(void) noexcept': attempting to reference a deleted function

My hunch was that that's because of the fact that I now provide a custom constructor, which causes the default copy constructor to no longer be implicit defined.

So, I added this as well to the class declaration

Unit(const Unit<T, R, D>& U) = default;

However, I'm getting the same error. I'm not sure what I could be. I'm not sure which deleted function the compiler is referring to.

Any help would be appreciated

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Ben
  • 1,519
  • 23
  • 39

2 Answers2

6

The issue here is the exception guarantee of your type. Per this post/reference your default constructor is noexcept. When you add your own, you do not provide an exception specification so it is not noexcept. What you need to do is add that to your default constructor since std::atomic's default constructor is marked as noexcept

namespace Base
{
    template <typename T, typename R, typename D>
    class Unit
    {
    public:
        constexpr Unit() noexcept;
    private:
        T m_Value;
    };

    template <typename T, typename R, typename D>
    constexpr Unit<T, R, D>::Unit() noexcept :
        m_Value(T(0))
    {   }
}

int main() 
{
    std::atomic<Base::Unit<int, int, int>> foo;
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • Ah, I see. Indeed fixed. When providing an atomic with a class whose constructor is potentially throwing, does that cause atomic( const atomic& ) = delete to be called (and thus, throwing the error above) – Ben Oct 07 '18 at 06:08
  • @ben, it causes `std::atomic::atomic(void) noexcept` to be called but it can't because the type could throw. The type you give to `std::atomic` needs to be trivially copyable and `noexcept` default constructable, of you want to default construct one. – NathanOliver Oct 07 '18 at 15:31
4

One workaround is to drop the constructor and use default member initializers:

template<class T>
struct Unit {
    T value = 0;
};

int main() {
    std::atomic<Unit<int>> a;
    std::atomic<Unit<int>> b = {{1}};
}
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271