1

By doing some code analysis in PVS-Studio, it gave me some warning messages.

I have the following statement in a header file:

constexpr int MIN_ALLOWED_Y { 0 };

And in a source file:

std::make_pair<const int, const int>( std::move( MIN_ALLOWED_Y ), std::move( MAX_ALLOWED_Y ) )

In the above expression, I used std::move to cast MIN_ALLOWED_Y to an xvalue because I thought std::make_pair only accepts rvalues;

// from https://en.cppreference.com/w/cpp/utility/pair/make_pair

template< class T1, class T2 >
constexpr std::pair<V1,V2> make_pair( T1&& t, T2&& u );

But I get warning messages like:

V833 Passing the const-qualified object 'MIN_ALLOWED_Y' to the 'std::move' function disables move semantics.

Is this a valid warning? If so then what should I do? Should I remove the std::move (maybe it's redundant in this case?)?

A better question would be where not to use std::move?

digito_evo
  • 3,216
  • 2
  • 14
  • 42

2 Answers2

5

Your code:

std::make_pair<const int, const int>( std::move( MIN_ALLOWED_Y ), std::move( MAX_ALLOWED_Y ) )

Is overly complicated. Not only are the moves pointless as PVS Studio told you, but using make_pair when explicitly specifying the types is pointless. You can simplify to:

std::pair<const int, const int>( MIN_ALLOWED_Y, MAX_ALLOWED_Y )

Which does the same thing without excess ceremony.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • 1
    I wonder if those two `const`s are even needed. Or maybe the type should be `const std::pair`. I suppose that's more of a question for the OP though. – David Grayson Dec 19 '21 at 07:16
  • I'm confused about `make_pair`'s behavior. Isn't `MIN_ALLOWED_Y` an **lvalue**?? How are `make_pair`'s rvalue reference parameters able to bind to an lvalue? – digito_evo Dec 19 '21 at 07:39
  • @digito_evo: You don't need `make_pair` at all, and let's keep it to one question per question please. – John Zwinck Dec 19 '21 at 07:42
  • 1
    @digito_evo In the prototype of `make_pair` you looked at, the `&&` are "forwarding references", not rvalue references. – j6t Dec 19 '21 at 07:44
  • That's the reason I used `std::move`. I thought I have to pass rvalues in order for make_pair to work. – digito_evo Dec 19 '21 at 07:46
  • 1
    No, you don't have to use rvalues, and you aren't benefitting from make_pair anyway, since you're passing explicit template type parameters. – John Zwinck Dec 19 '21 at 07:48
  • @John Zwinck Thanks. And BTW, switching to `std::pair` won't have any performance downsides, right? – digito_evo Dec 19 '21 at 08:07
  • 1
    Right, the compiler is more than smart enough to optimize both to the same thing. In fact, `make_pair` is less direct, so you might wonder if using `pair` directly would be faster...but they'll be the same if you have optimization enabled at build time. – John Zwinck Dec 19 '21 at 08:31
3

It sounds like you wrote std::move(MIN_ALLOWED_Y) somewhere and you got a warning about it from a static analyzer. Yes, I would remove the std::move because it doesn't make any sense to move a constant somewhere else.

Move semantics are for moving around C++ objects where it might impossible or expensive to copy the data/resources contained in the object. The object that was the source of the data in the move operation is possibly changed by the move, but it's impossible for your constant to change.

David Grayson
  • 84,103
  • 24
  • 152
  • 189