I have a function that takes an std::optional
void foo(const std::optional<T>& opt);
But copying T is expencive.
Does this create a copy of T?
If so, how can I not create a copy?
As clarified by your follow up comment, you are calling the function foo like this:
T t;
...
foo({t});
In this case, the answer is yes. A copy of t will be created. To avoid that, you can use std::reference_wrapper to avoid copying:
void foo(const std::optional<std::reference_wrapper<const T>> &optT) {
...
}
With these changes to the function, calling the it in the same manner will not result in creation of a copy.
Yes, std::optional stores a copy of whatever you pass to it. The C++17 standard explicitly prohibits storing references in std::optional. See: https://en.cppreference.com/w/cpp/utility/optional#:~:text=There%20are%20no%20optional%20references
As suggested by others, passing std::optional<std::reference_wrapper<const T>> is one way to avoid making copies.
void foo(const std::optional<std::reference_wrapper<const T>>& opt) {
if (opt) {
// Do something.
}
}
T t;
foo(t);
But consider that the C++ committee had good reasons for disallowing references in std::optional. For instance, an "optional reference" essentially describes what a plain pointer does, and plain pointers don't suffer from the long type name.
void foo(const T* opt) {
if (opt) {
// Do something.
}
}
T t;
foo(&t);
I think you will find useful this documentation page. See the section about "Optional function parameters".
When you call the function and pass an instance of T, an optional will be constructed which will own its own copy of T, therefore it will call T's copy constructor.
int main()
{
T t;
optional<T> ot;
foo(t); // will create a copy
foo(ot); // won't create a copy
}
If you're using boost::optional, not std::optional, you can declare foo as receiving an optional reference, i.e.
void foo(boost::optional<const T&> t)
Related
I have a C++ framework which I provide to my users, who should use a templated wrapper I wrote with their own implementation as the templated type.
The wrapper acts as an RAII class and it holds a pointer to an implementation of the user's class.
To make the user's code clean and neat (in my opinion) I provide a cast operator which converts my wrapper to the pointer it holds. This way (along with some other overloads) the user can use my wrapper as if it is a pointer (much like a shared_ptr).
I came across a corner case where a user calls a function, which takes a pointer to his implementation class, using std::move on my wrapper. Here's an example of what it looks like:
#include <iostream>
using namespace std;
struct my_interface {
virtual int bar() = 0;
};
template <typename T>
struct my_base : public my_interface {
int bar() { return 4; }
};
struct my_impl : public my_base<int> {};
template <typename T>
struct my_wrapper {
my_wrapper(T* t) {
m_ptr = t;
}
operator T*() {
return m_ptr;
}
private:
T* m_ptr;
};
void foo(my_interface* a) {
std::cout << a->bar() << std::endl;
}
int main()
{
my_impl* impl = new my_impl();
my_wrapper<my_impl> wrapper(impl);
foo(std::move(wrapper));
//foo(wrapper);
return 0;
}
[This is ofcourse just an example of the case, and there are more methods in the wrapper, but I'm pretty sure that don't play a role here in this case]
The user, as would I, expect that if std::move was called on the wrapper, then after the call to foo the wrapper will be empty (or at least modified as if it was moved), but in reality the only method being invoked before foo is the cast operator.
Is there a way to make the call to foo distinguishable between the two calls to foo i.e when calling with and without std::move?
EDIT
Thanks to the Mooing Duck's comment I found a way that my_wrapper knows which call is required, but I'm really not sure this is the best method to go with and will appreciate comments on this as well:
Instead of the previous cast operator use the following two:
operator T*() & {
return m_ptr;
}
operator T*() &&{
//Do something
return m_ptr;
}
now operator T*() && is called when calling with std::move and operator T*() & is called when calling without it.
The user, as would I, expect that if std::move was called on the wrapper, then after the call to foo the wrapper will be empty (or at least modified as if it was moved)
Your expectation is wrong. It will only be modified if a move happens, i.e. if ownership of some kind of resource is transferred. But calling foo doesn't do anything like that, because it just gets access to the pointer held inside the wrapper. Calling std::move doesn't do anything except cast its argument to an rvalue, which doesn't alter it. Some function which accepts an rvalue by reference might modify it, so std::move enables that, but it doesn't do that itself. If you don't pass the rvalue to such a function then no modification takes place.
If you really want to make it empty you can add an overload to do that:
template<typename T>
void foo(my_wrapper<T>&& w) {
foo(static_cast<my_interface*>(w));
w = my_wrapper<T>{}; // leave it empty
}
But ... why? Why should it do that?
The wrapper isn't left empty if you do:
my_wrapper<my_impl> w(new my_impl);
my_wrapper<my_impl> w2 = std::move(w);
And isn't left empty by:
my_wrapper<my_impl> w(new my_impl);
my_wrapper<my_impl> w2;
w2 = std::move(w);
If copying an rvalue wrapper doesn't leave it empty, why should simply accessing its member leave it empty? That makes no sense.
Even if your wrapper has a move constructor and move assignment operator so that the examples above do leave w empty, that still doesn't mean that accessing the member of an rvalue object should modify the object. Why does it make any logical difference whether the operator T* conversion is done to an lvalue or an rvalue?
(Also, are you really sure that having implicit conversions both to and from the wrapped pointer type is a good idea? Hint: it's not a good idea. In general prefer to make your conversions explicit, especially if you're dealing with pointers to dynamically-allocated objects.)
About std::move, here is what I can interpret, according to http://en.cppreference.com/w/cpp/utility/move :-
If I want to transfer ownership, I have to call std::move (or in rare case, std::forward).
Responsibility of std::move is calling operator=(A&& other).
The most essential step of the move operation is supposed to be implemented in operator=(A&&).
It is tricky to ensure that operator=(A&&) would be called. It need a special converter.
There are only two converters in the C++ world that can convert variables into xvalue (the &&) : std::move and std::forward.
Question
After adding many of std::move(std::unique_ptr) in my code, I start to worry that for such basic feature like transfer ownership, I have to heavily rely on the standard library (std::).
Do I really have to use std::move to transfer ownership?
Is spamming and hard-code calling std::move in many places of code-base a correct way to go for a high-standard program?
Should std::move be encapsulated?
They are actually a single question, but ask in different perspectives.
Edit
As request, here is my trial & error. It compiled ok.
I have no problem about the code, but I worry about its approach / pattern.
https://ideone.com/y8Pcgf
class T{
public: int value;
public: T(int a=1234){
value = a;
}
};
int main() {
std::unique_ptr<T> t1 = std::unique_ptr<T>(new T(1));
void* databaseNew=operator new [](sizeof(std::unique_ptr<T>));
std::unique_ptr<T>* t1ptr=static_cast<std::unique_ptr<T>*>(databaseNew);
new (t1ptr) std::unique_ptr<T>(std::move(t1));
return 0;
}
Rule of thumb:
If you're in a deduced x-value context, use std::forward:
template<class T>
void foo(T&& t) // T is deduced x-value, so we forward it
{
bar(std::forward<T>(t));
}
Otherwise use std::move
template<class T>
void foo1(std::vector<T> v) // although vector<T> is deduced, it's not an x-value
{
bar(std::move(v)); // so move it
}
template<class T>
void foo2(std::vector<T>&& v) // although vector<T> is deduced, it's not an x-value.
// In this case an r-value reference
{
bar(std::move(v)); // so move it
}
template<class T>
void foo3(std::vector<T>& v) // although vector<T> is deduced, it's not an x-value.
// In this case an l-value reference
{
bar(std::move(v)); // so move it
}
void foo4(std::vector<int> v) // complete type
{
bar(std::move(v)); // so move it
}
void foo5(std::vector<int> const & v) // const reference
{
bar(v); // not much point in moving it. std::move would cast it
// to std::vector<int> const&&, which although is detectable
// decays to std::vector<int> const&
}
which although is detectable... what?
It is permissible, if not necessarily advisable to write code like this:
#include <iostream>
struct X
{
void foo() const &
{
// do one thing...
std::cout << "one thing\n";
}
void foo() const &&
{
// do something else...
std::cout << "or another\n";
}
};
int main()
{
const X x;
x.foo();
std::move(x).foo();
}
const r-value references do exist, it's just that no-one uses them because there is no reasonable use-case.
The need to explicitly move, of which you complain, was actually done on purpose. Before unique_ptr, STL had a horrid construct called auto_ptr. It would move ownership impllicitly, and was borderline unusable unless you really really really knew what you were doing.
To make things more usable, in most cases C++ now requires you to explicitly state that you intend on moving ownership over a container, by using std::move.
In fact, std::move is little more than a cast to an rvalue reference.
There are cases where such an explicit specification is not necessary. For example, if the container from which you take ownership is already an rvalue (e.g. - a temporary object), then no case using std::move is necessary. For example, the following doesn't compile:
std::unique_ptr<int> a;
a = new int;
But the following does, without needing a move:
std::unique_ptr<int> a;
a = std::unique_ptr<int>(new int);
The reason this does not need a call to std::move, despite invoking the move operator, is that the object we move the ownership away from is already a temporary object (i.e. - an rvalue), so no cast is necessary.
Another example is if you call a function that returns a unique_ptr. You might have to call std::move inside the function to get it into the return value, but you do not need to call std::move on the function's return value to get it into the outside unique_ptr. It is already an rvalue, and therefor no cast is necessary.
Say I have:
f(T& t){ ... }
which I sometimes want to provide argument for from a function call
T GetT() { ... }
like this:
f(GetT())
Which won't compile even though I'm convinced that the lifetime of T is guaranteed to last until the end of expression, I also cannot change the T& to const T& because I need to modify the object inside f.
I thought about using T&& but then when I happen to have lvalue of T I would need to move() it, which would make it awkward because I sometimes need to use T after the call to f. In my case T is plain old data so I guess it would work but it doesn't feel right to move an object and use it afterwards.
Is there an elegant way to allow function to take both rval and lval refs to mutable object?
ATM I'm just doing
T t = GetT();
f(t);
Which I feel is at least one useless line and one useless copy of T.
How about using universal references.
Not sure if you would consider it elegant but it would look something like this:
struct MyStruct
{
int i;
};
template<class T>
void foo(T&& t)
{
static_assert(std::is_base_of<MyStruct,
typename std::remove_reference<T>::type>::value, "ERROR");
t.i = 1024;
}
MyStruct GetMyStruct()
{
return MyStruct();
}
int main()
{
foo(GetMyStruct());
MyStruct ms;
foo(ms);
return 0;
}
The way that you're currently doing, i.e. storing the object in a variable, is a proper way to extend the lifetime of the returned object and allow non-const references to bind to it. If GetT is implemented so that (N)RVO is possible, then no useless copy need to be made because it can be elided.
I came up with a solution to my problem with simple overload:
f(T& t) { ... }
f(T&& t) { f(t); }
But there still has to be a better way.
You cannot bind a reference to a temporany: only const reference can do that.
I suggesto you to look this link C++11 binding rules for const &&
Suppose there is a function that returns any local object, which implements move semantics, e.g. any STL container such as std::vector, std::string, etc. E.g.:
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
By default, tmp would be considered as an rvalue and tmp will be moved (or return value optimization will take place).
The question is how to manually override and avoid C++11's default behavior and execute copy constructor instead of move here? One solution may be to implement a wrapper class for std::vector with move semantics disabled, but this doesn't seem like a nice option.
One of the reasons for such desire may be that the caller is in another assembly and if the runtime libraries are statically linked, there would be two heaps. Moving will result in memory assertions due to allocation/deleting memory across DLLs boundaries.
The question is how to avoid C++11's default behavior and execute copy constructor instead of move here?
That isn't the default behaviour. The default behaviour would be to elide the copy in this case. The move would only take place in the unlikely case that the implementation does not implement NRVO.
The short answer is, you cannot make return f; not move. When you return in C++, elision is default, and if not that it is moved, and if not that it is copied. If you use a non-trivial statement -- even true?v:v, or static_cast<whatever const&>(v) -- it will prevent auto-move and force a copy. But that won't help you.
Avoiding the move won't help you. The return object is still created within the function, and it is disposed of by the calling code.
Now, not all is lost. You can avoid this by the use of header files (which exist within the client code) doing the allocation, and a DLL-safe interface (to the implementation).
Here I design a sink type, which sucks in data of type T, in batches. It then calls some function pointer with a pvoid and is done.
template<class T>
struct sink {
void* s;
void(*)(void*, T const*, T const*) f;
void operator()(T const& t)const{ f(s, &t, (&t)+1); }
void operator()(std::initializer_list<T> il) {
f(s, il.begin(), il.end());
}
};
template<class T, class A>>
sink<T> vector_sink( std::vector<T, A>& out ) {
return {&out, +[](void* s, T const* b, T const* e){
auto* pout = static_cast<std::vector<T,A>*>(s);
pout->insert( pout->end(), b, e );
}};
}
now, export from the DLL:
void make_data(sink<int> s) {
s({1,2,3,4,5});
}
in a header file, expose:
void make_data(sink<int> s);
std::vector<int> return_vector() {
std::vector<int> r;
make_data( vector_sink(r) );
}
and now the vector lives completely in the client code of the DLL. Only a standard layout class (consisting of 2 pointers) crosses the DLL barrier.
A fancier sink could distinguish between rvalues and lvalues by just adding a new function (for move-data-in). However, that seems unwise if this is intended to bridge DLL boundaries.
This handles "returning" a vector. To take a vector in (without appending), I'd advise writing array_view<int> which wraps two int*s: similarly, standard layout that is pretty safe to cross DLL boundaries with.
Performing a static_cast to reference will do
(example use movable class C, which can be vector)
cast to lvalue reference disables both move and NRVO
C f() {
C c;
return static_cast<C&>(c);
}
cast to rvalue reference disables just NRVO
C f() {
C c;
return static_cast<C&&>(c);
}
In traditional C++, passing by value into functions and methods is slow for large objects, and is generally frowned upon. Instead, C++ programmers tend to pass references around, which is faster, but which introduces all sorts of complicated questions around ownership and especially around memory management (in the event that the object is heap-allocated)
Now, in C++11, we have Rvalue references and move constructors, which mean that it's possible to implement a large object (like an std::vector) that's cheap to pass by value into and out of a function.
So, does this mean that the default should be to pass by value for instances of types such as std::vector and std::string? What about for custom objects? What's the new best practice?
It's a reasonable default if you need to make a copy inside the body. This is what Dave Abrahams is advocating:
Guideline: Don’t copy your function arguments. Instead, pass them by value and let the compiler do the copying.
In code this means don't do this:
void foo(T const& t)
{
auto copy = t;
// ...
}
but do this:
void foo(T t)
{
// ...
}
which has the advantage that the caller can use foo like so:
T lval;
foo(lval); // copy from lvalue
foo(T {}); // (potential) move from prvalue
foo(std::move(lval)); // (potential) move from xvalue
and only minimal work is done. You'd need two overloads to do the same with references, void foo(T const&); and void foo(T&&);.
With that in mind, I now wrote my valued constructors as such:
class T {
U u;
V v;
public:
T(U u, V v)
: u(std::move(u))
, v(std::move(v))
{}
};
Otherwise, passing by reference to const still is reasonable.
In almost all cases, your semantics should be either:
bar(foo f); // want to obtain a copy of f
bar(const foo& f); // want to read f
bar(foo& f); // want to modify f
All other signatures should be used only sparingly, and with good justification. The compiler will now pretty much always work these out in the most efficient way. You can just get on with writing your code!
Pass parameters by value if inside the function body you need a copy of the object or only need to move the object. Pass by const& if you only need non-mutating access to the object.
Object copy example:
void copy_antipattern(T const& t) { // (Don't do this.)
auto copy = t;
t.some_mutating_function();
}
void copy_pattern(T t) { // (Do this instead.)
t.some_mutating_function();
}
Object move example:
std::vector<T> v;
void move_antipattern(T const& t) {
v.push_back(t);
}
void move_pattern(T t) {
v.push_back(std::move(t));
}
Non-mutating access example:
void read_pattern(T const& t) {
t.some_const_function();
}
For rationale, see these blog posts by Dave Abrahams and Xiang Fan.
The signature of a function should reflect it's intended use. Readability is important, also for the optimizer.
This is the best precondition for an optimizer to create fastest code - in theory at least and if not in reality then in a few years reality.
Performance considerations are very often overrated in the context of parameter passing. Perfect forwarding is an example. Functions like emplace_back are mostly very short and inlined anyway.