2

I've recently started upgrading my current projects from VS2015 to VS2019 and VS2019 is a lot more restrictive about some things. One thing I have an issue with in particular is the way I'm currently releasing the memory of vectors:

std::vector<int> v(10);
v.swap(std::vector<int>()); // v should now be empty with no memory held

This worked fine in VS2015 but in VS2019 it no longer works because the vector I swap with is constant and vector::swap() requires a reference. This behavior has changed recently and must be a problem for more people than me given that this is the recommended way of releasing the memory of a vector. MS docs on the issue: https://learn.microsoft.com/en-us/cpp/error-messages/compiler-errors-2/compiler-error-c2664?view=msvc-160

What is the new recommended way of releasing the memory of a vector if you can't swap it away?

DaedalusAlpha
  • 1,610
  • 4
  • 20
  • 33
  • 2
    Are you looking for `clear()` and `shrink_to_fit()`? Or you can simply ***assign*** an empty vector to this existing object, `v=std::vector{};`, no fancy swapping was ever needed to do this. – Sam Varshavchik Aug 20 '21 at 14:00
  • 3
    @SamVarshavchik `clear()` does not actually release the memory held by the vector and `shrink_to_fit()` is implementation defined so you can't trust that it will release the memory. – DaedalusAlpha Aug 20 '21 at 14:02

2 Answers2

5

Your doing it backwards. To clear and release the memory for a vector in a guaranteed way, declare a temporary vector and swap the vector that needs to be cleared into it. That would tun your code into

std::vector<int>{}.swap(v);

At the end of the expression, the temporary object will be destroyed, taking the memory of v with it.


The reason this work before is Microsoft had an evil extension that was on by default that allowed prvalues to bind to non-const lvalue references. With that extension no longer on, the old non-standard code is now rightly failing to compile.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • Why are you using `{}` brackets instead of `()` in `std::vector{}.swap(v);` ? – DaedalusAlpha Aug 20 '21 at 14:14
  • 1
    @DaedalusAlpha, it's a way of doing constructor calls to avoid most vexing parse issues. Even when MVP wouldn't be an issue, good to stick with `{}` for consistency. – ChrisMM Aug 20 '21 at 14:21
  • 1
    @DaedalusAlpha It doesn't really matter but I tend to use `{}` for temporary objects to make them look less like a function. – NathanOliver Aug 20 '21 at 14:25
1

vector I swap with is constant

It's not constant, but it's an anonymous temporary, so it can only bind to a const ref.

What is the new recommended way of releasing the memory of a vector if you can't swap it away?

Well, you can swap it away, if you want to stay backwards compatible and/or don't trust shrink_to_fit(). You just have to name your temporary:

{
  std::vector<int> tmp;
  v.swap(tmp);
}

(obviously the reversed anonymous swap in the other answer is neater, if you don't need to stay backwards-compatible with C++98).

Useless
  • 64,155
  • 6
  • 88
  • 132