【问题标题】:std::atomic<std::shared_ptr<T>> is not working in C++20?std::atomic<std::shared_ptr<T>> 在 C++20 中不起作用?
【发布时间】:2021-05-07 14:10:30
【问题描述】:

似乎C++20标准为std::atomic&lt;std::shared_ptr&lt;T&gt;&gt;添加了support。但是当我写这样的代码时:

#include <memory>
#include <iostream>
#include <atomic>

struct A{
};

int main() {
        std::cout << std::atomic<std::shared_ptr<A>>{}.is_lock_free();
}

我得到一个错误,shared_ptr&lt;&gt; 不是 可轻易复制的,这是真的。我知道std::atmoic&lt;&gt; 数据类型需要可轻松复制,但我认为这种专业化应该可以解决这个问题。

是我遗漏了什么还是 Clang 和 GCC 尚未添加对此专业化的支持?

【问题讨论】:

  • 您需要在编译器选项中启用 C++20,并且您需要确保 Clang/GCC 的版本已经实现了该功能。 Clang 似乎升级其 C++ 功能的速度相当缓慢。
  • @ALX23z 我已经在 clang 12 和 gcc 11.1 上尝试过这个,在 Godbolt 上使用 -std=c++20 并且都给出了同样的错误。
  • 根据this table Atomic std::shared_ptr 和 std::weak_ptr 仅支持 MSVC 19.27*
  • @MarekR 哦...我从未在 cpp ref 中看到过此页面。感谢您的链接。一个非常有用的。
  • 现在的人们太不耐烦了——如果等待符合标准的编译器的年数是个位数,我们曾经很高兴;-)

标签: c++ c++20


【解决方案1】:

由于这个专业化还没有在 gcc 和 clang 中实现,我决定自己做。此外,我使用 cpp 功能检查来使用它,直到编译器添加对这些方法的支持。

这段代码还没有测试。所以我想知道这段代码是否正确,尤其是wait()notify_one()notify_all()方法:

#include <atomic>
#include <memory>
#include <condition_variable>
#include <thread>
#include <version>

#if !defined(__cpp_lib_atomic_shared_ptr) || (__cpp_lib_atomic_shared_ptr == 0)

namespace std {

template<typename T> 
struct atomic<shared_ptr<T>> {

    using value_type = shared_ptr<T>;

    static constexpr bool is_always_lock_free = false;
    bool is_lock_free() const noexcept {
        return false;
    }

    constexpr atomic() noexcept {};
    atomic(shared_ptr<T> desired) noexcept : ptr_(std::move(desired)) {};
    atomic(const atomic&) = delete;
    void operator=(const atomic&) = delete;

    void store(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept {
        std::lock_guard<std::mutex> lk(cv_m_);
        atomic_store_explicit(&ptr_, std::move(desired), order);
    }
    void operator=(shared_ptr<T> desired) noexcept {
        store(std::move(desired));
    }

    shared_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept {
        return atomic_load_explicit(&ptr_, order);
    }
    operator shared_ptr<T>() const noexcept {
        return load();
    }

    shared_ptr<T> exchange(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept {
        return atomic_exchange_explicit(&ptr_, std::move(desired), order);
    }

    bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
                                memory_order success, memory_order failure) noexcept {
        return atomic_compare_exchange_weak_explicit(&ptr_, &expected, std::move(desired), success, failure);
    }
    bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
                                    memory_order success, memory_order failure) noexcept {
        return atomic_compare_exchange_strong_explicit(&ptr_, &expected, std::move(desired), success, failure);
    }
    bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
                                memory_order order = memory_order::seq_cst) noexcept {
        return compare_exchange_weak(expected, std::move(desired), order, convert_order(order));
    }
    bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
                                    memory_order order = memory_order::seq_cst) noexcept {
        return compare_exchange_strong(expected, std::move(desired), order, convert_order(order));
    }

    void wait(shared_ptr<T> old, memory_order order = memory_order::seq_cst) const noexcept {
        std::unique_lock<std::mutex> lk(cv_m_);
        cv_.wait(lk, [&]{ return !(load(order) == old); });
    }
    void notify_one() noexcept {
        cv_.notify_one();
    }
    void notify_all() noexcept {
        cv_.notify_all();
    }

private:
    shared_ptr<T> ptr_;
    mutable std::condition_variable cv_;
    mutable std::mutex cv_m_;

    constexpr memory_order convert_order(memory_order order) {
        switch(order) {
        case std::memory_order_acq_rel:
            return std::memory_order_acquire;
        
        case  std::memory_order_release:
            return std::memory_order_relaxed;

        default:
            return order;
        }
    }
};

}

#endif

int main() {
    std::atomic<std::shared_ptr<int>> a;
}

【讨论】:

    猜你喜欢
    • 2022-01-23
    • 2015-07-23
    • 2019-10-20
    • 2022-09-24
    • 2018-02-02
    • 1970-01-01
    • 2018-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多