C++標準 2015-02 mid-meetingのレビュー: N4370-N4380
N4370: Networking Library Proposal (Revision 4)
Boost.Asioを土台にしたネットワークライブラリの提案。
N4371: Minimal incomplete type support for standard containers, revision 2
一部のSTLのコンテナーの要素型に不完全型をサポートする提案。
以下のようなコードが書けるようになる。
struct Entry
{
std::vector<Entry> v ;
} ;
クラスは、定義の終了である}を持って、完全型になる。クラス定義内ではまだ不完全型である。したがって、vectorにテンプレート実引数に渡す時点では、まだ不完全型なのだ。これをサポートするかどうかは、これまで規格上は未規定だったのだが、この提案では、vector, list, forward_listに限ってはサポートするとしている。
これ以外のコンテナーについては、更に議論をして緩和していくという。
N4372: A Proposal to Add a Const-Propagating Wrapper to the Standard Library
クラスのデータメンバーがポインターの場合、ポインターの参照先は、constメンバー関数からでも変更できる。
struct A
{
void f() ;
void f() const ;
} ;
class B
{
std::unique_ptr<A> ptr ;
public :
// コンストラクターやデストラクターなど
void f()
{
ptr->f() ; // 非const版が呼ばれる
}
void f( ) const
{
ptr->f() ; // 非const版が呼ばれる
}
} ;
これは完全に規格通りの挙動だが、意味的にはここでconst版が呼ばれて欲しい。そこで、そのようなconst性を伝播させるライブラリ、propagate_constを提案している。
class B
{
std::propagate_const< std::unique_ptr<A> > ptr ;
public :
void f()
{
ptr->f() ; // 非const版が呼ばれる
}
void f( ) const
{
ptr->f() ; // const版が呼ばれる
}
} ;
N4373: Atomic View
非atomicオブジェクトをatomic操作できるラッパーライブラリ、atomic_viewの提案。
// 並列実行される何らかのタスク
void spawn_task( std::experimental::atomic_array_view<int> v ) ;
void f( int * ptr, std::size_t size )
{
// 非atomic操作
std::for_each( ptr, ptr + size, []( auto & elem ) { elem = 0 ; } ) ;
{
std::experimental::atomic_array_view<int> v( ptr, size ) ;
// vを経由してしか操作できない。
spawn_task( v ) ;
spawn_task( v ) ;
spawn_task( v ) ;
// vが破棄される
}
// これ以降、配列に直接操作が可能
}
atomic_array_view<T>は、既存の非アトミック型の配列をラップして、アトミックな操作ができるようにしてくれる。atomic_array_viewでラップする前に起こったアクセスは、atomic_array_viewのコンストラクターの実行が完了する前に起こる(happens before)。
atomic_array_viewのオブジェクトが存在する間は、配列に直接アクセスすることはできず、atomic_array_viewのオブジェクトを通してしかアクセスできない。
atomic_array_viewはコピーすることができる。その際には、アトミック操作を実現するためのロックなどのリソースが、もしあれば、共有される。最後のatomic_array_viewのオブジェクトが破棄された後に、元の配列は直接アクセスすることが出来るようになる。
配列ではなく単一のオブジェクトに対するarray_viewである、atomic_concurrenty_view<T>も存在する。
これらのatomic_viewには、二つの利用方法が想定されている。ひとつには、High Performance Computing用途で、巨大な配列を、まず競合しない方法で初期化し、次に並列に変更し、その後に競合しない方法で読み書きを行うような処理に使える。
もうひとつは、既存のコードで非atomicな型を使っていて、atomic<T>に置き換えるコストが現実的ではない場合に使うことができる。
N4374: Linux-Kernel Memory Model
これまで、Linuxカーネルのメモリーモデルは、memory-varriers.txtとatomic_ops.txtにラフにドキュメント化されていた。これはLinuxカーネルの開発には用を為すが、厳密な規格を書き起こすには不適切である。N4374は、初めてLinuxカーネルのメモリーモデルを厳密にドキュメントする試みである。
Linuxカーネルのメモリーモデルがまとめられていて、C++との対応も考察されている。Linuxカーネルで使われている既存のメモリーモデルをC++コミュニティに紹介することで、今後の規格化に役立てる意図がある。
N4375: Out-of-Thin-Air Execution is Vacuous
オブジェクトへの並列アクセスによる競合により、本来現れるはずのない値が現れてしまう、Out Of Thin Air(OOTA) Effectの具体的な例と、それに酔ってもたらされる害悪を紹介した論文。
N4376: Use Cases for Thread-Local Storage
TLSは20年以上も使われている実績ある機能ではあるが、最近、SIMD畑とGPGPU畑の連中が、TLSの有用性に疑問を持っていて、会議でもそう主張している。この論文はTLSの有用性を解説している。
ただし、SIMDやGPGPUによる軽いスレッド風並列処理を行う際に、TLSは共有する実装がもっとも効率的であり、悩ましいところで、論文ではそこの考察も行っている。
[PDF] N4377: C++ Extensions for Concepts PDTS
Concept Liteのドラフト
N4378: Language Support for Contract Assertions
契約プログラミングのためのcontract_assertライブラリ。
contract_assertには、3種類のassertion levelが設定されている。min, on, maxだ。minは最小限、maxは最大限のレベルになっている。これ以外にも、完全に無効にするoffがある。assertion levelは、何らかの実装依存の方法で設定するようだ。レベルは、コンパイル時にpredefine macroで取得することができる。
#ifdef contract_assertion_level_max
#endif
これは、従来のNDEBUGのようなマクロに相当する。
contract_assertには、contract_assert_min/contract_assert_on/contract_assert_maxがある。それぞれ、レベルに対応していて、そのレベル以上の場合にチェックが走る。contract_assertマクロは、contract_assert_onと同じだ。
void * contract_memcpy( void * dest, const void * src, size_t n )
{
// 軽い契約チェック
// nullポインターではないかどうか調べる
contract_assert( dest != nullptr ) ;
contract_assert( src != nullptr ) ;
// 重たい契約チェック
// 環境依存の方法を使って有効なメモリ領域かどうかを調べる
contract_assert_max( platform_specific::is_valid_memory_area( dest, n ) ) ;
contract_assert_max( platform_specific::is_valid_memory_area( src, n ) ) ;
char * d = static_cast<char *>(dest) ;
char const * s = static_cast<char const *>(src) ;
char const * const end = s + n ;
for ( ; s != end ; ++s, ++d )
{
*d = *s ;
}
// 重たい契約チェック
// 宇宙線やハードウェア破損などの可能性を考慮
contract_assert_max( std::memcmp( dest, src, n ) == 0 ) ;
return dest ;
}
契約違反時には、ハンドラーが呼ばれる。このハンドラーは呼び出し元にreturnしてはならない。デフォルトのハンドラーは、std::abortを呼び出す。set_contract_violation_handlerでカスタムハンドラーを設定できる。
int main()
{
std::experimental::set_contract_violation_handler(
[]( std::experimental::contract_violation_info & info )
{
// assertionレベルを表すenum値
// enum class contract_assertion_level { min, on, max };
auto level = info.level ;
// contract_assertの式の文字列
// contract_assert( is_okay(x) ) ;の場合、"is_oaky(x)"
// phase 3なので、プリプロセッサーマクロ展開前の文字列が得られる
// 複数の連続した空白文字はスペース文字ひとつになる。
std::cout << info.expression_text << '\n' ;
// contract_assertが存在するソースファイルの__FILE__
std::cout << info.filename << '\n' ;
// contract_assertが存在するソースファイルの__LINE__に相当
std::cout << info.line_number << '\n' ;
// ハンドラーは呼び出し元に戻ってはならない
std::abort() ;
} ) ;
}
contract_violation_infoクラスのメンバーの中でも、expression_textが興味深い。Phase of translationのphase 3の文字列なので、マクロも展開されない。また、複数の連続した空白文字(スペース、改行、水平タブ、垂直タブ、ラインフィード)は、スペースひとつに変換される。
#define identity(x) x
// "identity ( x ) "
contract_assert(
identity
(
x
)
) ;
C++としてはだいぶ頑張ったようだ。
[PDFうざい] N4379: FAQ about N4378, Language Support for Contract Assertions
contract_assertに対するFAQ集。
興味深いものを紹介すると・・・
contract_assertはコンパイル時チェックやデッドコード除去、最適化、静的解析用途にも使えるように設計されている。
どうやってデッドコード除去を行うのか?
コンパイラーにとってasssert式とシンボルを関連付けるのはお手の物だ。
なぜ関数本体でしか使えないのか?
それ以上のものは、全く経験のないまったく新しい文法や機能を必要とする。そこまで冒険したくない。
N4380: Constant View: A proposal for a std::as_const helper function template
<utility>にstd::as_constの提案。
int main()
{
std::string text("text") ;
std::string const & const_ref = std::as_const(text) ;
// std::string::const_iterator
auto iter = std::as_const(text).begin() ;
}
as_const(obj)は、以下のように実装できる
template< typename T >
inline typename std::add_const< T >::type &
as_const( T &t ) noexcept
{
return t;
}
as_constの提案理由としては、const版と非const版の同名のメンバー関数がある場合、const版のメンバー関数を明示的に呼び出すことだ。
int main()
{
std::string s ;
// std::string::iterator
auto iter1 = s.begin() ;
// std::string::const_iterator
auto iter2 = std::as_const(s).begin()
}
cbeginはこの目的のためにあるが、すべてのクラスに存在するわけではない。const版のメンバー関数を明示的に呼ぶ際に、const_cast< std::add_const< decltype( object ) >::type & >( object )と書くより楽になる。
xvalueやprvalueをサポートすることに意義があるかという点について、議論が分かれている。
ドワンゴ広告
この記事はドワンゴ勤務中に書かれた。
どうやら、ドワンゴ社内に競技プログラミング部なるものができるそうだ。
ドワンゴは本物のC++プログラマーを募集しています。
CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0