Suppose I have a vector:
std::vector<uint64_t> foo;
foo.push_back(1);
foo.push_back(27);
I pass this vector to a function by reference.
calculate_something(foo);
int calculate_something(std::vector<uint64_t>& vec) {
// ...
}
In rare circumstances, the function needs to locally modify the vector, in which case a copy must be made. Is this the correct way to do that?
if (some_condition) {
vec = vec;
}
vec.push_back(7);
Edit: The reason I am self-assigning is because assigning to another variable results in a copy and my intuition tells me that the same would occur when assigning back to the same variable.
CodePudding user response:
No, it is not correct.
Assignment in C doesn't create new objects or change what object a reference refers to. Assignment only changes the value of the object to which the left-hand side refers (either through a built-in assignment operator or through the conventional behavior of operator=
overloads).
In order to create new objects that persist longer than the evaluation of an expression, you need a declaration of some variable. Such a declaration can have an initializer using =
which is often confused for assignment, which it is not:
std::vector<uint64_t> vec2 = vec;
This creates a new object vec2
of type std::vector<uint64_t>
and initializes it with vec
, which implies copying vec
's state into vec2
. This is not assignment! If you write instead
vec2 = vec;
then you have assignment which modifies the state of the object named vec2
to be equal to that of the object referred to by vec
. But in order to do that there has to be already a declaration for vec2
in which the vector object itself has been created. The assignment is not creating a new object.
If you simply use
vec = vec;
then there is only one object, the one that vec
refers to. It is non-obvious whether this assignment is allowed at all, but even in the best case all it could do is copy the state of the object that vec
refers to into the object that vec
refers to, meaning that at the end the state of vec
should simply be unchanged and there is no other side effect.
In general you can't rebind a name or a reference in C to a new object.
So what you want is
std::vector<uint64_t> local_vec = vec;
and then you can use local_vec
as a local copy of vec
. You can avoid having to specify the type by using auto
to indicate that you want the variable to have the same type as the right-hand side (minus reference and const
qualifiers):
auto local_vec = vec;
CodePudding user response:
In rare circumstances, the function needs to locally modify the vector, in which case a copy must be made. Is this the correct way to do that?
If you need a copy vec = vec
does not help. No matter if =
skips selfassignement, after that line vec
still refers to the parameter that the caller passed to the function.
If the function needs a copy rather than a reference, pass the vector by value:
int calculate_something(std::vector<uint64_t> vec) {
// ...
}
If you need both, a reference and a copy then pass by reference and make a copy:
int calculate_something(std::vector<uint64_t>& vec) {
auto copy = vec;
// ...
}
CodePudding user response:
Additionally as to what others have said, copy assignment operators in C are typically (but not mandatory) implemented as below:
SomeClass& operator=(const SomeClass& other)
{
if (this != &other)
{
// copy the properties of other to this
}
return *this;
}
So a self-assignment has no effect.