ПроблемаЭта проблема происходит, когда значение исходного объекта читается после того, как его содержимое перемещено в целевой объект путем вызова std::move
функционируйте явным образом. 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
.
Исходный объект имеет встроенный базовый тип, такой как: int
, enum
, float
'double'
, указатель, std::intptr_t
, std::nullptr_t
.
РискПоскольку состояние исходного объекта обычно не задано после операции пересылки, небезопасно выполнить операции, которые используют состояние исходного объекта после операции пересылки. Доступ к состоянию исходного объекта после операции пересылки может привести к нарушению целостности данных, неожиданному значению или недопустимому разыменованию указателя.
ФиксацияИзбегайте операций, которые могут считать исходный объект после того, как его содержимое перемещено.
Пример — чтение значения исходного объекта после вызова std::move
#include<string>
#include<iostream>
void F1()
{
std::string s1{"string"};
std::string s2{std::move(s1)};
// ...
std::cout
<< // Noncompliant
s1
<< "\n";
// value after move operation
}
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));
}
}
В функциональном F1
, строка s1
явным образом перемещен в s2
путем вызова std::move
. После операции пересылки функция пытается считать s1
. Polyspace отмечает эту попытку чтения исходного объекта после явного перемещения.
В функциональном F3
, строка s
явным образом перемещен и затем это читается std::string::append
функция. Polyspace отмечает эту попытку чтения исходного объекта после явного перемещения.
Коррекция — значения чтения исходных объектов в заданном состоянии#include<string>
#include<iostream>
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 F4()
{
for (unsigned i = 0; i < 10; ++i) {
std::string s(1, static_cast<char>('0' + i)); // Compliant
g(std::move(s));
}
}
В функциональном F2
, уникальный указатель ptr1
явным образом перемещен в ptr2
. Поскольку состояние std::unique_ptr
остается в заданном состоянии после перемещения, читая источник уникальный указатель после того, как явное перемещение будет совместимо.
В функциональном F4
, строка s
явным образом перемещен. В каждой итерации цикла, s
инициируется к определенному содержимому, прежде чем операция пересылки будет инициирована. В результате состояние s
задан, прежде чем к объекту получают доступ. Этот метод доступа к исходному объекту после операции пересылки совместим с этим правилом.