正确支持 STL 中成员函数的 volatile 限定符
Proper support of volatile qualifier of member functions in STL
STL 中 volatile-qualified 成员函数重载的不正确支持阻止以通用方式使用容器、智能指针等。比如说,我想声明一个包装器 class,它提供值语义并允许基础类型的不完整性:
#include <type_traits>
#include <utility>
#include <memory>
template< typename type >
struct recursive_wrapper
{
using value_type = type;
template< typename ...arguments >
recursive_wrapper(arguments &&... _arguments)
: storage_(std::make_unique< type >(std::forward< arguments >(_arguments)...))
{ ; }
operator type & () & noexcept
{
return *storage_;
}
operator type const & () const & noexcept
{
return *storage_;
}
operator type && () && noexcept
{
return std::move(*storage_);
}
operator type const && () const && noexcept
{
return std::move(*storage_);
}
operator volatile type & () volatile & noexcept
{
return *storage_;
}
operator volatile type const & () volatile const & noexcept
{
return *storage_;
}
operator volatile type && () volatile && noexcept
{
return std::move(*storage_);
}
operator volatile type const && () volatile const && noexcept
{
return std::move(*storage_);
}
private :
std::unique_ptr< type > storage_;
};
// file:main.cpp
#include <iostream>
#include <vector>
#include <cstdlib>
int
main()
{
struct A;
struct B { recursive_wrapper< A > a; };
struct A { std::vector< B > b; };
{ // basic usage
B b;
A & a = b.a; // OK
static_cast< void >(a);
}
// let's add cv-qualifiers
{
volatile B b;
volatile A & a = b.a; // error!
static_cast< void >(a);
}
return EXIT_SUCCESS;
}
缺少适当的 volatile-qualified 重载 std::unqie_ptr::operator * ()
导致错误:
main.cpp:38:16: error: indirection requires pointer operand ('volatile std::unique_ptr<A>' invalid)
return *storage_;
^~~~~~~~~
main.cpp:83:30: note: in instantiation of member function 'recursive_wrapper<A>::operator volatile A &' requested here
volatile A & a = b.a;
^
1 error generated.
相同的故事 WRT std::container::push_back()
、size()
等
它完全阻止了在使用 volatile
成员函数限定符的通用代码中使用 STL 的对象(不涉及 const_cast
运算符)。
如此糟糕的 STL 设计决策的原因是什么?为什么 volatile
成员函数限定符在 STL 中没有得到正确支持? volatile
成员函数限定符是否被删除?
"Poor design decision"?并不真地。该关键字是从 C 继承而来的,但在今天已经很少用到它了。它并没有被积极弃用,但它的主要用途是在简单的情况下。内存映射硬件就是一个很好的例子。但是不会有内存映射 std::deque<>
所以 STL 对此的支持没有什么意义。
这是一个非常好的决定。这是因为对于大多数类型而言,波动性 完全错误。
请记住,对象上的 volatile
意味着 对象的字段可以自发变异。
考虑以下情况,并假设系统保证在任何给定时刻,begin
和 end
将指向同一内存块:
template<class T>
class vector
{
T *begin;
T *end;
vector(vector const volatile &other) : begin(other.begin), end(other.end) { ... }
};
原来vector::vector(vector const volatile &)
是错误的,因为不能保证同时读取begin
和end
因此,它创建的副本可能有 begin
和 end
不同步,即使原始副本完全没问题。
我想这应该足以让你明白为什么 volatile
很少被使用了。
它的使用原因与您可能期望使用的原因相同(即原子)。
它的用例是完全不同和不常见的,它不是你随心所欲地使用 const
.
的方式。
STL 中 volatile-qualified 成员函数重载的不正确支持阻止以通用方式使用容器、智能指针等。比如说,我想声明一个包装器 class,它提供值语义并允许基础类型的不完整性:
#include <type_traits>
#include <utility>
#include <memory>
template< typename type >
struct recursive_wrapper
{
using value_type = type;
template< typename ...arguments >
recursive_wrapper(arguments &&... _arguments)
: storage_(std::make_unique< type >(std::forward< arguments >(_arguments)...))
{ ; }
operator type & () & noexcept
{
return *storage_;
}
operator type const & () const & noexcept
{
return *storage_;
}
operator type && () && noexcept
{
return std::move(*storage_);
}
operator type const && () const && noexcept
{
return std::move(*storage_);
}
operator volatile type & () volatile & noexcept
{
return *storage_;
}
operator volatile type const & () volatile const & noexcept
{
return *storage_;
}
operator volatile type && () volatile && noexcept
{
return std::move(*storage_);
}
operator volatile type const && () volatile const && noexcept
{
return std::move(*storage_);
}
private :
std::unique_ptr< type > storage_;
};
// file:main.cpp
#include <iostream>
#include <vector>
#include <cstdlib>
int
main()
{
struct A;
struct B { recursive_wrapper< A > a; };
struct A { std::vector< B > b; };
{ // basic usage
B b;
A & a = b.a; // OK
static_cast< void >(a);
}
// let's add cv-qualifiers
{
volatile B b;
volatile A & a = b.a; // error!
static_cast< void >(a);
}
return EXIT_SUCCESS;
}
缺少适当的 volatile-qualified 重载 std::unqie_ptr::operator * ()
导致错误:
main.cpp:38:16: error: indirection requires pointer operand ('volatile std::unique_ptr<A>' invalid)
return *storage_;
^~~~~~~~~
main.cpp:83:30: note: in instantiation of member function 'recursive_wrapper<A>::operator volatile A &' requested here
volatile A & a = b.a;
^
1 error generated.
相同的故事 WRT std::container::push_back()
、size()
等
它完全阻止了在使用 volatile
成员函数限定符的通用代码中使用 STL 的对象(不涉及 const_cast
运算符)。
如此糟糕的 STL 设计决策的原因是什么?为什么 volatile
成员函数限定符在 STL 中没有得到正确支持? volatile
成员函数限定符是否被删除?
"Poor design decision"?并不真地。该关键字是从 C 继承而来的,但在今天已经很少用到它了。它并没有被积极弃用,但它的主要用途是在简单的情况下。内存映射硬件就是一个很好的例子。但是不会有内存映射 std::deque<>
所以 STL 对此的支持没有什么意义。
这是一个非常好的决定。这是因为对于大多数类型而言,波动性 完全错误。
请记住,对象上的 volatile
意味着 对象的字段可以自发变异。
考虑以下情况,并假设系统保证在任何给定时刻,begin
和 end
将指向同一内存块:
template<class T>
class vector
{
T *begin;
T *end;
vector(vector const volatile &other) : begin(other.begin), end(other.end) { ... }
};
原来vector::vector(vector const volatile &)
是错误的,因为不能保证同时读取begin
和end
因此,它创建的副本可能有 begin
和 end
不同步,即使原始副本完全没问题。
我想这应该足以让你明白为什么 volatile
很少被使用了。
它的使用原因与您可能期望使用的原因相同(即原子)。
它的用例是完全不同和不常见的,它不是你随心所欲地使用 const
.