メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

AUTOSAR C++14 Rule A12-8-3

Moved-from object shall not be read-accessed

R2021a 以降

説明

ルール定義

Moved-from object shall not be read-accessed.

根拠

一般的に、ソース オブジェクトの内容は移動演算後に不明確になるため、移動演算後にソース オブジェクトの内容にアクセスする演算の実行は危険です。移動演算後にソース オブジェクトの内容にアクセスすると、データ整合性違反、予期しない値、またはポインターの不正なデリファレンスにつながる可能性があります。

オブジェクトの状態に関する前提を持たない演算はこのルールに違反しません。

C++ 標準では、以下の移動演算では移動後にソース オブジェクトを明確に指定された状態にするように規定されています。

  • 1 std::unique_ptr 型の移動構築、移動代入、移動構築の変換、移動代入の変換

  • std::shared_ptr 型の移動構築、移動代入、移動構築の変換、移動代入の変換

  • std::shared_ptr 型の std::unique_ptr からの移動構築と移動代入

  • std::weak_ptr 型の移動構築、移動代入、移動構築の変換、移動代入の変換

  • std::basic_ios 型の std::move()

  • std::basic_filebuf 型の移動コンストラクターと移動代入

  • std::thread 型の移動コンストラクターと移動代入

  • std: unique_lock 型の移動コンストラクターと移動代入

  • std::shared_lock 型の移動コンストラクターと移動代入

  • std::promise 型の移動コンストラクターと移動代入

  • std::future 型の移動コンストラクターと移動代入

  • std::shared_future 型の移動構築、移動代入、移動構築の変換、移動代入の変換

  • std::packaged_task 型の移動コンストラクターと移動代入

これらの移動演算はソース オブジェクトを明確に指定された状態のままにするため、これらの関数の呼び出し後のソース オブジェクトへのアクセスはこのルールに準拠しています。

Polyspace 実装

関数 std::move を明示的に呼び出すことによってソース オブジェクトの内容が宛先オブジェクトに移動されてから、ソース オブジェクトが読み取られる場合に、Polyspace® はフラグを設定します。Polyspace は、以下の場合のソース オブジェクトへのアクセスにフラグを設定しません。

  • 明示的な移動操作のソース オブジェクトは、以下の型のオブジェクトです。

    • std::unique_ptr

    • std::shared_ptr

    • std::weak_ptr

    • std::basic_ios

    • std::basic_filebuf

    • std::thread

    • std::unique_lock

    • std::shared_lock

    • std::promise

    • std::future

    • std::shared_future

    • std::packaged_task

  • 移動演算は暗黙的に実行されます。たとえば、関数 std::remove は暗黙的にオブジェクトを移動します。Polyspace は、暗黙的に移動されたオブジェクトへのアクセスにフラグを設定しません。移動されたオブジェクトに誤ってアクセスすることを回避するには、std::erase を使用して削除済みオブジェクトを消去します。std::remove の使用についての詳細は、[非プロパーな erase-remove の用法] を参照してください。

  • ソース オブジェクトは、次のような組み込みの基本型のオブジェクトです。intenumfloatdouble、pointer、std::intptr_tstd::nullptr_t

トラブルシューティング

ルール違反が想定されるものの、Polyspace から報告されない場合は、コーディング規約違反が想定どおりに表示されない理由の診断を参照してください。

すべて展開する

この例では、明示的な移動演算後のソース オブジェクトの読み取りに、Polyspace がどのようにフラグを設定するかを示します。

#include<string>
#include<iostream>
void F1()
{
	std::string s1{"string"};
	std::string s2{std::move(s1)}; 
	// ...
	std::cout
	<<  // Noncompliant
	s1
	<< "\n";
}

void F2()
{
	std::unique_ptr<std::int32_t> ptr1 = std::make_unique<std::int32_t>(0);
	std::unique_ptr<std::int32_t> ptr2{std::move(ptr1)};
	std::cout << ptr1.get() << std::endl; // Compliant by exception
}
void g(std::string v)
{
	std::cout << v << std::endl; 
}

void F3()
{
	std::string s;
	for (unsigned i = 0; i < 10; ++i) {
		s.append(1, static_cast<char>('0' + i));  //Noncompliant 
		g(std::move(s));
	}
}
void F4()
{
	for (unsigned i = 0; i < 10; ++i) {
		std::string s(1, static_cast<char>('0' + i)); // Compliant
		g(std::move(s));  
	}
}

  • 関数 F1 では、std::move を呼び出すことによって、文字列 s1s2 に明示的に移動されます。移動演算後に、この関数は s1 を読み取ろうとします。Polyspace は、この明示的な移動後のソース オブジェクトの読み取りの試みにフラグを設定します。

  • 関数 F2 では、ユニーク ポインター ptr1ptr2 に明示的に移動されます。std::unique_ptr は移動後も特定の状態にあるため、明示的な移動後のソース ユニーク ポインターの読み取りはこのルールに準拠しています。

  • 関数 F3 では、文字列 s が明示的に移動されてから関数 std::string::append によって読み取られます。Polyspace は、この明示的な移動後のソース オブジェクトの読み取りの試みにフラグを設定します。

  • 関数 F4 では、文字列 s が明示的に移動されます。ループの反復ごとに、移動操作がトリガーされる前に、s が特定の内容に初期化されます。そのため、オブジェクトがアクセスされる前に s の状態が指定されます。この移動操作の後のソース オブジェクトへのアクセス方法はこのルールに準拠しています。

チェック情報

グループ: 特殊なメンバー関数
カテゴリ: Required、Partially automated

バージョン履歴

R2021a で導入


1 A converting constructor is a constructor that is not declared with the specifier explicit. See Converting constructor.