Reputation: 969
In Rust, non-primitive types are not copied, but are moved by default. This is great, because they're expensive to copy.
struct Post { title: String, content: String };
let (title, content) = ("some title".to_string(), "very long post...".to_string()); // imagine they're from the user
let post = Post { title, content };
// can longer access `title` and `content`
If you really want a copy, it's simple: just clone
it (although in 99% of the cases you don't actually need to copy, and clone()
signifies an anti-pattern):
let post = Post { title: title.clone(), content: content.clone() };
If you write similar code in C++:
class Post {
string title, content;
public:
Post(string t, string c) : title{ t }, content{ c }{};
};
int main() {
string title = "some title";
string content = "very long post...";
Post post(title, content);
}
The strings get copied.
I know there is std::move
, but the ergonomics isn't very good, as demonstrated in this post. The author also suggested using shared_ptr
, but that would cause a quite large overhead (about the same as Rust's Arc
).
So the questions are, is it possible to mimic Rust's move semantics in C++? Is it idiomatic to do that? If not, what are the commonly used practices to prevent copying non-primitive objects in C++?
Upvotes: 0
Views: 423
Reputation: 7498
There are two ways in C++ to prevent implicit copying.
As the type author, you can delete the copy constructor and copy assignment operator. This disallows copying even when the copy is explicit. It is heavy-handed.
As the type consumer, you can take an rvalue reference:
void foo(T&& t)
If foo
is passed a temporary, an implicit move happens. If a copy is wanted, one can make an explicit copy either naming the type or using something like the copy
function below. If someone wants to pass a non-temporary, both move and copy must be explicit.
// one way to make a copy explicit
T copy(const T& t) { return t; }
foo(copy(get_t()));
Upvotes: 3