3

This code compiles cleanly and works with all compilers I've tried except for GCC 8 (and current GCC trunk):

std::make_shared<volatile int>(0)

I'd like to know:

  1. Is GCC 8 correct to refuse this code?
  2. Is there a substitute that GCC 8 will accept (with the same semantics and performance)? I am aware of std::atomic, but the semantics are not the same so suggestions to use it instead of volatile are not what I'm looking for.

See it here: https://godbolt.org/z/rKy3od

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • Just to be clear: you are aware that `volatile` won't give you any sort of thread safety, and don't guarantee there won't be optimizations? – Guillaume Racicot Sep 11 '18 at 04:58
  • 1
    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57403 – smac89 Sep 11 '18 at 05:00
  • 2
    `I am aware of std::atomic, but the semantics are not the same so suggestions to use it instead of volatile are not what I'm looking for.` what semantic are you looking for? I would be easier to find subtitutes for you. – Guillaume Racicot Sep 11 '18 at 05:06
  • That bug was on 4.8. – P.W Sep 11 '18 at 05:07
  • @GuillaumeRacicot: Yes I am aware of what `volatile` does and does not do. – John Zwinck Sep 11 '18 at 05:24
  • 1
    IDK your use case, but the following workaround, accepted even by GCC 4.8, might work for you (adding `volatile` is completely safe and `static_pointer_cast` works as well): `std::const_pointer_cast(std::make_shared(0))` – Arne Vogel Sep 11 '18 at 09:03
  • 2
    @ArneVogel: Thanks for the tip. This seems to work OK: `shared_ptr p = make_shared(0)`. – John Zwinck Sep 11 '18 at 09:38

1 Answers1

5

According to the standard language this is a libstdc++ non conformance.

This is probably a mistake. make_shared calls allocate_shared with a standard allocator, std::allocator<remove_const_t<T>> where T is the type of the shared object. This allocator will only be used to get a rebinded allocator for the underlying shared object (a struct which contains the volatile int and atomic counters). So it is perfectly fine to declare this underlying object as non const non volatile.

This definition for make_shared will work:

template<class T,class...Args>
auto make_shared(Args&&...args){
    using ncvT= std::remove_cv_t<T>;
    return std::allocate_shared<T>(std::allocator<ncvT>(),std::forward<Args>(args)...);
}
Oliv
  • 17,610
  • 1
  • 29
  • 72