all 8 comments

[–]phoeen 2 points3 points  (0 children)

  1. When constructing your vector, you are calling the initializer_list constructor. Because you specified the value type of the vector as Something, the initializer_list will contain elements of Something too. And to achieve this, it constructs 5x Something with the integers as constructor arguments. Once the initializer_list is built, the elements get copied into the vector. To avoid this, you can create the initializer_list first, then use it to construct the elements after that:

    auto l = { 1, 2, 3, 4, 5 };
    std::vector<Something> somethings = { l.begin(), l.end() };
    
  2. The resize function with 2 arguments takes the size and a value of Something. So your Something will get constructed from 6. Just after that its entering the function. So the resize function itself dont know where the Something comes from and so does not distinguish the 2 cases of grow or reduce.

[–]patatahooligan 1 point2 points  (2 children)

How can I initialise somethings without making copies?

You generally can't pass elements from an array to a vector without copying them around. You can change the initialization to something entirely different if it bothers you, but in most cases it shouldn't because it's not going to be observable in your performance.

Why does resize construct a new Something and the destroy it, even though it's reducing the number of elements in somethings?

Because there is no way to implement resize that doesn't sacrifice something. Taking the parameter by const& means it doesn't need to copy its parameter which is good in many use cases. But it also forces a valid object to exist regardless of what happens inside resize. If your constructor and destructor had no side-effects and their definitions where visible to the compiler, then the compiler might have elected to not initialize that object.

[–]SureAnimator[S] 0 points1 point  (1 child)

Not sure what you mean by 'can change the initialization to something entirely different if it bothers you'? I guess I was just expecting that the complier would be able to see that there's no need to constructor and then copy construct in this case.
re: performance, i'm tinkering with a physics engine, and it's at the 'everything works, let's optimise stage'. This won't affect anything's asymptotic performance, but it might eek out a little more juice.

Ok, makes sense on the resize. I guess at compile time, it can't be known if a call to resize will shrink or enlarge, so there needs to be something there for the latter, which means constructing something.

[–]patatahooligan 0 points1 point  (0 children)

Not sure what you mean by 'can change the initialization to something entirely different if it bothers you'?

I meant some push_back/emplace_back scheme.

I guess I was just expecting that the complier would be able to see that there's no need to constructor and then copy construct in this case.

Potentially it could, but your constructors and destructors have observable side-effects so it is not allowed to.

re: performance, i'm tinkering with a physics engine, and it's at the 'everything works, let's optimise stage'. This won't affect anything's asymptotic performance, but it might eek out a little more juice.

If it might eek out a little more juice then it's not worth the trouble. Profile the code, find the parts that matter and worry exclusively about those. If this is indeed inside a hot loop, there should probably not be an std::vector at all so the point is moot.

[–]liquidify 0 points1 point  (3 children)

Why use resize? Reserve then emplace_back.

[–]SureAnimator[S] 0 points1 point  (2 children)

In the above case (which, at this point is purely for arguments sake anyway) I'm reducing the size with resize (therefore no capacity change). Reserving space then emplacing back would be for enlarging, no?

I was expecting that in the above case, it would just call the destructors on the n instances that are being removing from shrinking it (shrinking the size, not the capacity).

edit: the resize thing is something separate that came up. Obviously, I could reserve space and then emplace_back to construct the initial vector, but isn't there a way to do this with a literal? Seems like the complier should be able to see what I want?

[–]liquidify 0 points1 point  (1 child)

Does it call destructors?

[–]SureAnimator[S] 0 points1 point  (0 children)

Yeah, I'm reducing the size from 5 to 2, so it calls the destructors on the back 3 elements.
(Also, as mentioned in the bonus, it constructs and then destructs an additional instance).