Первоначально я предполагал, что перемещать эталонный параметр l-значения - плохая практика.Действительно ли это общепринято сообществом разработчиков C ++?
Когда я вызываю функцию, имеющую ссылочный параметр R-значения, ясно, что я должен ожидать, что переданный объект может быть перемещен.Для функции, имеющей параметр ссылки на L-значение, это не так очевидно (и до того, как семантика перемещения была введена в C ++ 11, это вообще было невозможно).
Однако некоторые другие разработчикиЯ недавно говорил, чтобы не согласиться с тем, что следует избегать перемещения ссылок на l-значение.Есть ли веские аргументы против этого?Или мое мнение неверно?
Поскольку меня попросили предоставить пример кода, вот один (см. Ниже).Это искусственный пример только для демонстрации проблемы.Очевидно, что после вызова modifyCounter2 () вызов getValue () вызовет ошибку сегментации.Однако, если бы я был пользователем getValue (), не зная его внутренней реализации, я был бы очень удивлен.Если бы, с другой стороны, параметр был ссылкой на R-значение, я бы совершенно ясно, что я не должен больше использовать объект после вызова modifyCounter2 ().
class Counter
{
public:
Counter() : value(new int32_t(0))
{
std::cout << "Counter()" << std::endl;
}
Counter(const Counter & other) : value(new int32_t(0))
{
std::cout << "Counter(const A &)" << std::endl;
*value = *other.value;
}
Counter(Counter && other)
{
std::cout << "Counter(Counter &&)" << std::endl;
value = other.value;
other.value = nullptr;
}
~Counter()
{
std::cout << "~Counter()" << std::endl;
if (value)
{
delete value;
}
}
Counter & operator=(Counter const & other)
{
std::cout << "operator=(const Counter &)" << std::endl;
*value = *other.value;
return *this;
}
Counter & operator=(Counter && other)
{
std::cout << "operator=(Counter &&)" << std::endl;
value = other.value;
other.value = nullptr;
return *this;
}
int32_t getValue()
{
return *value;
}
void setValue(int32_t newValue)
{
*value = newValue;
}
void increment()
{
(*value)++;
}
void decrement()
{
(*value)--;
}
private:
int32_t* value; // of course this could be implemented without a pointer, just for demonstration purposes!
};
void modifyCounter1(Counter & counter)
{
counter.increment();
counter.increment();
counter.increment();
counter.decrement();
}
void modifyCounter2(Counter & counter)
{
Counter newCounter = std::move(counter);
}
int main(int argc, char ** argv)
{
auto counter = Counter();
std::cout << "value: " << counter.getValue() << std::endl;
modifyCounter1(counter); // no surprises
std::cout << "value: " << counter.getValue() << std::endl;
modifyCounter2(counter); // surprise, surprise!
std::cout << "value: " << counter.getValue() << std::endl;
return 0;
}