微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何以原子方式复制不可复制的类型

如何解决如何以原子方式复制不可复制的类型

我正在编写一个 Atom 类,因为类型 T 不是简单可复制的。我想知道我下面的 load() 和 store() 实现是否会导致竞争条件。

class Atom {
    // Assumptions:
    // 1. atomic<T> is not natively supported
    // 2. T does not contain any interior-pointers (pointers pointing to a field
    //    in the structure or the struct itself)
    // 3. T is neither trivially-copyable nor trivially-destructible
    // 4. T's copy constructor is thread-safe; i.e. The object being copied is not
    //    mutated without synchronization.

    using LT = typename std::aligned_storage<sizeof(T),alignof(T)>::type;

    spin::MRSWLock<T> locked_object;  // a multiple-reader-single-writer spinlock

    template<class... Args,class = std::enable_if_t<std::is_constructible_v<T,Args...>>>
    explicit Atom(Args&&... args): locked_object(std::forward<Args>(args)...) {}

    T load() const {
        LT l;
        {
            auto x = locked_object.read(); // get read lock

            // make a bitwise/shallow copy of object
            l = *reinterpret_cast<const LT*>(&*x);

        } // object unlocked here when x goes out of scope

        // make a deep copy of the object here by calling copy constructor.
        return T(*reinterpret_cast<const T*>(&l));
    }

    template<class... Args,Args...>>>
    void store(Args&&... args) const {
        LT l,m;
        // construct the new object
        new (&l) T(std::forward<Args>(args)...);
        {
            auto x = locked_object.write(); // get write lock

            // make a bitwise-copy of the current object
            m = *reinterpret_cast<const LT*>(&*x);

            // make bitwise-assign of the new value of the object
            *reinterpret_cast<LT*>(&*x) = l;

        }// object unlocked here as x goes out of scope

        // destroy old object here.
        reinterpret_cast<T*>(&m)->~T();
    }
};

如果可能存在竞争条件,有没有办法在对象被锁定时复制该对象而不调用其复制构造函数

解决方法

您的代码充满错误。

m = reinterpret_cast<const LT*>(&*x);

在这里你将一个指针分配给一个非指针。

l = reinterpret_cast<const LT*>(&*x);

一次又一次。

如果我试图读懂你的想法并忽略你的代码而是遵循注释,不,使用对象的字节副本作为不可简单复制的对象是UB。期间。

复制一个不能简单复制的对象需要运行它的复制构造函数。

销毁不存在的物体

reinterpret_cast<T*>(&m)->~T();

也是UB。

您似乎落入了一个陷阱,即只有简单地映射到汇编指令才能确定 C++ 代码的含义和正确性。

C++ 是根据抽象机器定义的,该机器知道对象在哪里以及它们的类型是什么。编译器可能不完全知道此信息,它可能不会直接显示在生成的程序集中,但违反其规则是 UB,编译器可以并且确实使用该信息以破坏程序的方式更改生成的程序集,如果您打破规则。

最糟糕的是,您不知道哪个编译器更新或标志会破坏通过测试的代码,可能会以时间旅行等疯狂的方式破坏。 (是的,在 C++ 中,UB 被允许在运行前进行时间旅行和破解代码)。

不要使用UB。维护成本太高。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。