Reputation: 2719
I have been searching for this matter on SO and other sources but I couldn't wrap my head around this issue. Using resouces of rvalues and xvalues somewhat new to C++ (with C++11).
Now, do we - C programmers - miss something here? Or there is a corresponding technique in C to benefit from these resource efficiency?
EDIT: This quesiton is not opinion based whatsoever. I just couldn't describe my question. What I am asking is that whether or not there is a corresponding technique in c.
Upvotes: 8
Views: 3335
Reputation: 8579
No. You have to roll-your-own but like other features of C++ (e.g. polymorphism) you can effect the same semantics but with more coding:
#include<stdlib.h>
typedef struct {
size_t cap;
size_t len;
int* data;
} vector ;
int create_vector(vector *vec,size_t init_cap){
vec->data=malloc(sizeof(int)*init_cap);
if(vec->data==NULL){
return 1;
}
vec->cap=init_cap;
vec->len=0;
return 0;
}
void move_vector(vector* to,vector* from){
//This effects a move...
to->cap=from->cap;
to->len=from->len;
free(to->data);
to->data=from->data;//This is where the move explicitly takes place.
//Can't call destroy_vec() but need to make the object 'safe' to destroy.
from->data=NULL;
from->cap=0;
from->len=0;
}
void destroy_vec(vector *vec){
free(vec->data);
vec->data=NULL;
vec->cap=0;
vec->len=0;
}
Notice how in the move_vector()
the data
is (well…) moved from one vector to another.
The idea of handing resources between objects is common in C and ultimately amounts to 'move semantics'. C++ just formalised that, cleaned it up and incorporated it in overloading.
You may well even have done it yourself and don't realise because you didn't have a name for it. Anywhere where the 'owner' of a resource is changed can be interpreted as 'move semantics'.
Upvotes: 4
Reputation: 21136
C doesn't have a direct equivalent to move semantics, but the problems that move semantics solve in c++ are much less common in c: As c also doesn't have copy constructors / assignment operators, copies are by default shallow, whereas in c++ common practice is to implement them as deep copy operations or prevent them in the first place.
C also doesn't have destructors and the RAII pattern, so transferring ownership of a resource comes up less frequently.
Upvotes: 1
Reputation: 129314
I don't believe it's move semantics that C is missing. It's all the C++ functionality leading up to move semantics that is "missing" in C. Since you can't do automatic struct copies that call functions to allocate memory, you don't have a system for automatically copy complex and expensive data structures.
Of course, that's the intention. C is a more light-weight language than C++, so the complexity of creating custom copy and assignment constructors is not meant to be part of the language - you just write code to do what needs to be done as functions. If you want "deep copy", then you write something that walks your data structure and allocates memory, etc. If you want shallow copy, you write something that copies the pointers in the data structure to the other one (and perhaps setting the source ones to NULL
) - just like a move semantics constructor does.
And of course, you only need L and R value in C (it is either on the left or the right of an = sign), there are no references, and clearly no R value references. This is achieved in C by using address of (turning things into pointers).
So it's not really move semantics that C is missing, it's the complex constructors and assignment operators (etc) that comes with the design of the C++ language that makes move semantics a useful thing in that language. As usual, languages evolve based on their features. If you don't have feature A, and feature B depends on feature A being present, you don't "need" feature B.
Of course, aside from exception handling and const references [and consequently R value references in C++11, which is esentially a const reference that you are allowed to modify], I don't think there is any major feature in C++ that can't be implemented through C. It's just a bit awkward and messy at times (and will not be as pretty syntactically, and the compiler will not give you neat error messages when you override functions the wrong way, you'll need to manually cast pointers, etc, etc). [After stating something like this, someone will point out that "you obviously didn't think of X", but the overall statement is still correct - C can do 99.9% of what you would want to do in C]
Upvotes: 5
Reputation: 40604
The C equivalent to C++ move semantics would be to pass a struct
by value, and then to proceed with throwing away the original object without destructing it, relying on the destruction of the copy to be correct.
However, this is very error prone in C, so it's generally avoided. The closest to move semantics that we actually do in C, is when we call realloc()
on an array of structs, relying on the bitwise copy to be equivalent to the original. Again, the original is neither destructed nor ever used again.
The difference between the C style copy and C++ move semantics is, that move semantics modify the original, so that its destructor may safely be invoked. With the C bitwise copy approach, we just forget about the contents of the original and don't call a destructor on it.
These more strict semantics make C++ move semantics much easier and safer to use than the C style copy and forget. The only drawback of C++ move semantics is, that it's slightly slower than the C style copy and forget approach: Move semantics copy by element rather than bitwise, then proceed to modify the original, so that the destructor becomes a semantical noop (nevertheless, it's still called). C style copy and forget replace all this by a simple memcpy()
.
Upvotes: 0
Reputation: 320381
Of course, there is a similar technique in C. We have been doing "move semantics" in C for ages.
Firstly, "move semantics" in C++ is based on a bunch of overload resolution rules that describe how functions with rvalue reference parameters behave during overload resolution. Since C does not support function overloading, this specific matter is not applicable to C. You can still implement move semantics in C manually, by writing dedicated data-moving functions with dedicated names and explicitly calling them when you want to move the data instead of copying it. E.g, for your own data type struct HeavyStruct
you can write both a copy_heavy_struct(dst, src)
and move_heavy_struct(dst, src)
functions with appropriate implementations. You'll just have to manually choose the most appropriate/efficient one to call in each case.
Secondly, the primary purpose of implicit move semantics in C++ is to serve as an alternative to implicit deep-copy semantics in contexts where deep copying is unnecessarily inefficient. Since C does not have implicit deep-copy semantics, the problem does not even arise in C. C always performs shallow copying, which is already pretty similar to move semantics. Basically, you can think of C as an always-move language. It just needs a bit of manual tweaking to bring its move semantics to perfection.
Of course, it is probably impossible to literally reproduce all features of C++ move semantics, since, for example, it is impossible to bind a C pointer to an rvalue. But virtually everything can be "emulated". It just requires a bit more work to be done explicitly/manually.
Upvotes: 15