Modifying unnamed objects via r-value semantics - c++

I have a method that modifies objects passed by reference:
class MyClass;
MyClass& modify (MyClass& x) { ...; return x; }
What's the right way to extend modify to unnamed objects avoiding extra copies, so that the following code is valid?
MyClass createMyClass () { ... }
MyClass x = modify(createMyClass());
// instead of:
MyClass x = createMyClass();
modify(x);
PS: MyClass implements efficient moving.

It seems this code works with perfect forwarding, but not sure if you like it or not:
#include <memory>
#include <iostream>
struct T {
T() {std::cout << this << " ctor\n";}
~T() {std::cout << this << " dtor\n";}
T(const T& t) {std::cout << this << " cc\n"; i = t.i;}
T(T&& t) {std::cout << this << " mc\n"; i = t.i;}
T& operator=(const T& t) {std::cout << this << " ca\n"; i = t.i; return *this;}
T& operator=(T&& t) {std::cout << this << " ma\n"; i = t.i; return *this;}
int i = 0;
};
//T& modify (T& t) {t.i++; return t; }
template<typename X>
X modify (X&& t) { t.i++; return t; }
T create_T () { return T{}; }
int main() {
T t1 = modify(create_T());
std::cout << t1.i << "\n----------\n";
// instead of:
T t2 = create_T();
modify(t2);
std::cout << t2.i << "\n";
return 0;
}
And output will be like this:
0x7fff616d0fe0 ctor
0x7fff616d0fe8 mc
0x7fff616d0fe0 dtor
1
----------
0x7fff616d0fd8 ctor
1
0x7fff616d0fd8 dtor
0x7fff616d0fe8 dtor
You can also replace prefect forwarding with these 2 lines:
T& modify (T& t) { t.i++; return t; }
T modify (T&& t) { t.i++; return t; }
but not very interesting method.
Update:
For the reason that I don't know, following code does not generate similar output like perfect forwarding:
auto modify (auto&& t) { t.i++; return t; }
and output will be like this:
0x7ffcfa65c9a8 ctor
0x7ffcfa65c9b0 mc
0x7ffcfa65c9a8 dtor
1
----------
0x7ffcfa65c9a8 ctor
0x7ffcfa65c9b8 cc
0x7ffcfa65c9b8 dtor
1
0x7ffcfa65c9a8 dtor
0x7ffcfa65c9b0 dtor
Maybe the more experienced ones can tell the reasoning behind this difference.

Related

why child class can convert lvalue to rvalue? in c++ perfect forwarding

using namespace std;
class Data {
public:
Data() {}
~Data() {}
Data(const Data& t) { cout << "Copy Constructor" << endl; }
Data(Data&& t) noexcept { cout << "Move Constructor" << endl; }
Data& operator=(const Data& t) {
cout << "Copy =" << endl;
return *this;
}
Data& operator=(Data&& t) noexcept {
cout << "Move =" << endl;
return *this;
}
};
class Data2 : public Data {};
class Test {
public:
void setData(std::shared_ptr<Data>&& d) { data = std::forward<std::shared_ptr<Data>>(d); }
private:
std::shared_ptr<Data> data;
};
int main() {
Test t;
auto d = std::make_shared<Data>();
t.setData(d); // error
t.setData(move(d)); // ok
auto d1 = std::make_shared<Data2>();
t.setData(d1); // why ok????????????
int debug = 0;
}
Why doesn't t.setData(d1) require std::move to convert d1 to an rvalue but t.setData(d) doesn't compile?
t.setData(d1) has to convert d1 to std::shared_ptr<Data>, it does this by copying into a temporary value. Temporary values are already rvalues so don't require an explicit std::move.
Note that as d1 is passed via a temporary conversion setData doesn't alter d1, you still need to use std::move for this to happen so that d1 is moved into the temporary rather than being copied. E.g in:
auto d = std::make_shared<Data>();
t.setData(std::move(d));
std::cout << d.get() << "\n";
auto d1 = std::make_shared<Data2>();
t.setData(d1);
std::cout << d1.get() << "\n";
auto d2 = std::make_shared<Data2>();
t.setData(std::move(d2));
std::cout << d2.get() << "\n";
d and d2 will end up as null pointers but d1 will still point to the object.
Note that in std::forward<std::shared_ptr<Data>>(d) as you know the exact type of d std::forward is unnecessary and you could just use std::move(d) instead.

Capturing lambda in std::function results in extra copies

I am trying to write some code which allows me to call a function at some later time by storing the function call and its arguments in a lambda/std::function. Ideally, the arguments would only be copied ONCE (and moved oterhwise) but the smallest number of copies I can achieve seems to be 2.
//==============================================================================
// INCLUDES
//==============================================================================
#include <iostream>
#include <functional>
#include <memory>
//==============================================================================
// VARIABLES
//==============================================================================
static std::unique_ptr<std::function<void()>> queueFunction;
//==============================================================================
// CLASSES
//==============================================================================
class Test {
public:
Test(int a, int b = 20, int c = 30) : _a(a), _b(b), _c(c) {
std::cout << "Test: Constructor" << std::endl;
}
~Test() {
std::cout << "Test: Destructor" << std::endl;
}
Test(const Test& other) :
_a(other._a)
{
std::cout << "Test: Copy Constructor" << std::endl;
}
Test(Test&& other) :
_a(std::move(other._a))
{
std::cout << "Test: Move Constructor" << std::endl;
}
Test& operator=(const Test& other) {
if (this != &other) {
_a = other._a;
std::cout << "Test: Assignment Operator" << std::endl;
}
return *this;
}
Test& operator=(Test&& other) {
if (this != &other) {
_a = std::move(other._a);
std::cout << "Test: Move Assignment Operator" << std::endl;
}
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const Test& v) {
os << "{a=" << v._a << "}";
return os;
}
private:
int _a;
int _b;
int _c;
};
//==============================================================================
// FUNCTIONS
//==============================================================================
void foo(const Test& t);
void _foo(const Test& t);
template <typename F>
void queue(F&& fn) {
std::cout << "queue()" << std::endl;
queueFunction = std::make_unique<std::function<void()>>(std::forward<F>(fn));
}
void dequeue() {
std::cout << "dequeue()" << std::endl;
if (queueFunction) {
(*queueFunction)();
}
queueFunction.reset();
}
void foo(const Test& t) {
std::cout << "foo()" << std::endl;
queue([t](){
_foo(t);
});
//Only a single copy of Test is made here
/*
[t](){
_foo(t);
}();
*/
}
void _foo(const Test& t) {
std::cout << "_foo()" << std::endl;
std::cout << "t=" << t << std::endl;
}
//==============================================================================
// MAIN
//==============================================================================
int main() {
std::cout << "main()" << std::endl;
Test test1(20);
foo(test1);
dequeue();
std::cout << "main() return" << std::endl;
return 0;
}
The output of the above code is:
main()
Test: Constructor
foo()
Test: Copy Constructor
queue()
Test: Copy Constructor
Test: Copy Constructor
Test: Destructor
Test: Destructor
dequeue()
_foo()
t={a=20}
Test: Destructor
main() return
Test: Destructor
Which makes no sense to me. Shouldn't the lambda capture the instance of Test once, then forward that lambda all the way to the new std::function thus causing a move?
If I modify my queue function as such I can at least get rid of once copy.
void queue(std::function<void()> fn) {
std::cout << "queue()" << std::endl;
queueFunction = std::make_unique<std::function<void()>>(std::move(fn));
}
Output:
main()
Test: Constructor
foo()
Test: Copy Constructor
Test: Copy Constructor
queue()
Test: Destructor
dequeue()
_foo()
t={a=20}
Test: Destructor
main() return
Test: Destructor
But I still cannot understand where the extra copy is coming from.
Can someone help to enlighten me?
AFAICT the problem is the const of the foo() argument. When you capture t inside foo(const Test& t), then the type of that capture inside the lambda is also const. Later when you forward the lambda, the lambda's move constructor will have no choice but copy, not move, the capture. You cannot move from const.
After changing foo to foo(Test& t) I get:
main()
Test: Constructor
foo()
Test: Copy Constructor
queue()
Test: Move Constructor
Test: Move Constructor
Test: Destructor
Test: Destructor
dequeue()
_foo()
t={a=20}
Test: Destructor
main() return
Test: Destructor
Alternative solution, mentioned in https://stackoverflow.com/a/31485150/85696, is to use capture in the form [t=t].
With move-capture and two other changes it is possible to eliminate this remaining copy constructor too:
- void foo(const Test& t) {
+ void foo(Test t) {
...
- queue([t](){
+ queue([t = std::move(t)](){
...
- foo(test1);
+ foo(std::move(test1));
main()
Test: Constructor
Test: Move Constructor
foo()
Test: Move Constructor
queue()
Test: Move Constructor
Test: Move Constructor
Test: Destructor
Test: Destructor
Test: Destructor
dequeue()
_foo()
t={a=20}
Test: Destructor
main() return
Test: Destructor

Template customization point with default behavior to do nothing

I have a generic code at which point I leave a possibility to modify data.
if (impl_.mode() == implementation_type::manual)
{
const auto steering = custom::customize_steering(impl_, input.steering());
impl_.output_interface()(steering);
return impl_.do_continue(impl_.params().period());
}
By default I want customize_steering to be optimized out.
Now I have it this way:
template<typename ImplT, typename SteeringT>
constexpr std::decay_t<SteeringT> customize_steering(ImplT &, SteeringT &&steering)
{
return std::forward<SteeringT>(steering);
}
Is it the right way to do or is it too convoluted and passing by const reference will do fine?
I decided to check, and I don't get the results I expect.
#include <iostream>
class foo
{
public:
foo() { std::cout << "Constructed" << std::endl; }
foo(const foo &) { std::cout << "Copy constructed" << std::endl; }
foo(foo &&) { std::cout << "Move constructed" << std::endl; }
~foo() { std::cout << "Destroyed" << std::endl; }
};
template<typename T>
std::decay_t<T> do_nothing(T &&t)
{
return std::forward<T>(t);
// return t;
}
int main(int, char **)
{
const auto &fcr = do_nothing(do_nothing(do_nothing(foo())));
const auto fc = do_nothing(fcr);
return 0;
}
The output is (MinGW64):
Constructed
Move constructed
Move constructed
Move constructed
Destroyed
Destroyed
Destroyed
Copy constructed
Destroyed
Destroyed
What I expected:
Without mandatory copy elision: Constructor -> Move constructor.
With mandatory copy elision (C++17): Constructor (for const auto fc).
How can I make it work?

Different behavior needed if template template parameter is vector

We are using one internal c++ library that takes std::vector as input however i want to write wrapper function that should be able to accept std::vector, std::set or std::unordered_set but when input passed to this wrapper function is std::vector itself i don't want to copy that in temporary vector so is there any way to avoid this unnecessary copy.
Sample Reference code will explain this issue with more clarity :
#include <iostream>
#include <set>
#include <vector>
#include <unordered_set>
void print(const std::vector<int>& argVec)
{
for(auto elem:argVec)
{
std::cout<<elem<<std::endl;
}
}
template<template<typename...>class VecOrSet>
void wrapper(const VecOrSet<int>& input)
{
//How to avoid this temporary vector if input argument is vector itself
std::vector<int> temp(input.begin(),input.end());
print(temp);
}
int main()
{
std::vector<int> v{1,2,3};
std::set<int> s{4,5,6};
std::unordered_set<int> us{7,8,9};
wrapper(v);
wrapper(s);
wrapper(us);
return 0;
}
You can add a full specialization.
template<>
void wrapper(const std::vector<int>& input)
{
print(input);
}
Or just add another overload.
void wrapper(const std::vector<int>& input)
{
print(input);
}
Or use constexpr if (since C++17).
template<template<typename...>class VecOrSet>
void wrapper(const VecOrSet<int>& input)
{
if constexpr (std::is_same_v<VecOrSet<int>, std::vector<int>>) {
print(input);
} else {
std::vector<int> temp(input.begin(),input.end());
print(temp);
}
}
Another solution could be initialize temp passing through another function: getIntVect(), with a generic version
template <typename VoS>
std::vector<int> getIntVect (VoS const & input)
{ return { input.cbegin(), input.cend() }; }
that copy the input in a std::vector<int>, and a specific version for std::version<int>
std::vector<int> const & getIntVect (std::vector<int> const & input)
{ return input; }
that return a const-reference to the input (that is: avoid the copy)
So, using decltype(auto),
template<template<typename...>class VecOrSet>
void wrapper(const VecOrSet<int>& input)
{
decltype(auto) temp { getIntVect(input) };
print( temp );
}
temp is a reference to input, when VecOrSet is std::vector, or a copy of input, otherwise.
-- EDIT --
The OP is dubious
I think this line decltype(auto) temp{getIntVect(input)}; will call copy constructor of vector if input is vector
This is true for auto temp{getIntVect(input)};, as pointed by T.C. (thanks!). Not for decltype(auto) temp{getIntVect(input)};
Try compiling and running the following code
#include <iostream>
struct A
{
A ()
{ std::cout << "- default constructor" << std::endl; }
A (A const &)
{ std::cout << "- copy constructor" << std::endl; }
A (A &&)
{ std::cout << "- move constructor" << std::endl; }
};
template <typename T>
A foo (T const &)
{ return {}; }
A const & foo (A const & a)
{ return a; }
int main ()
{
std::cout << "--- 000" << std::endl;
A a0;
std::cout << "--- 001" << std::endl;
auto a1 { foo(a0) };
std::cout << "--- 002" << std::endl;
decltype(auto) a2 { foo(a0) };
std::cout << "--- 003" << std::endl;
decltype(auto) a3 { foo(0) };
std::cout << "--- 004" << std::endl;
}
I get (from g++ and clang++) this output
--- 000
- default constructor
--- 001
- copy constructor
--- 002
--- 003
- default constructor
--- 004
As you can see, auto a1 { foo(a0) }; call the copy constructor of A (because auto become A and A a1 { foo(a0) }; cause the the copy of the value returned by foo()) but decltype(auto) a2 { foo(a0) }; doesn't call contructors (because decltype(auto) become A const & and A const & a2 { foo(a0) }; simply link a2 to foo(a0) (so to a0).

shared_ptr that cannot be null?

Using a std::shared_ptr expresses shared ownership and optionality (with its possibility to be null).
I find myself in situations where I want to express shared ownership only in my code, and no optionality. When using a shared_ptr as a function parameter I have to let the function check that it is not null to be consistent/safe.
Passing a reference instead of course is an option in many cases, but I sometimes would also like to transfer the ownership, as it is possible with a shared_ptr.
Is there a class to replace shared_ptr without the possibility to be null, some convention to handle this problem, or does my question not make much sense?
You are asking for not_null wrapper class. Fortunately your issue is already addressed by C++ experts guideline and there are already example implementations - like this one. Search for not_null class template.
You could write a wrapper around std::shared_ptr that only allows creation from non-null:
#include <memory>
#include <cassert>
template <typename T>
class shared_reference
{
std::shared_ptr<T> m_ptr;
shared_reference(T* value) :m_ptr(value) { assert(value != nullptr); }
public:
shared_reference(const shared_reference&) = default;
shared_reference(shared_reference&&) = default;
~shared_reference() = default;
T* operator->() { return m_ptr.get(); }
const T* operator->() const { return m_ptr.get(); }
T& operator*() { return *m_ptr.get(); }
const T& operator*() const { return *m_ptr.get(); }
template <typename XT, typename...XTypes>
friend shared_reference<XT> make_shared_reference(XTypes&&...args);
};
template <typename T, typename...Types>
shared_reference<T> make_shared_reference(Types&&...args)
{
return shared_reference<T>(new T(std::forward<Types>(args)...));
}
Please note that operator= is missing yet. You should definitely add it.
You can use it like this:
#include <iostream>
using std::cout;
using std::endl;
struct test
{
int m_x;
test(int x) :m_x(x) { cout << "test("<<m_x<<")" << endl; }
test(const test& t) :m_x(t.m_x) { cout << "test(const test& " << m_x << ")" << endl; }
test(test&& t) :m_x(std::move(t.m_x)) { cout << "test(test&& " << m_x << ")" << endl; }
test& operator=(int x) { m_x = x; cout << "test::operator=(" << m_x << ")" << endl; return *this;}
test& operator=(const test& t) { m_x = t.m_x; cout << "test::operator=(const test& " << m_x << ")" << endl; return *this;}
test& operator=(test&& t) { m_x = std::move(t.m_x); cout << "test::operator=(test&& " << m_x << ")" << endl; return *this;}
~test() { cout << "~test(" << m_x << ")" << endl; }
};
#include <string>
int main() {
{
auto ref = make_shared_reference<test>(1);
auto ref2 = ref;
*ref2 = test(5);
}
{
test o(2);
auto ref = make_shared_reference<test>(std::move(o));
}
//Invalid case
//{
// test& a = *(test*)nullptr;
// auto ref = make_shared_reference<test>(a);
//}
}
Output:
test(1)
test(5)
test::operator=(test&& 5)
~test(5)
~test(5)
test(2)
test(test&& 2)
~test(2)
~test(2)
Example on Coliru
I hope I didn't forget anything that might result in undefined behaviour.
After taking a look at GSL's not_null class, which calls std::terminate() instead of abort();
Here is how I achieved it:
template <typename T>
class NonNull : public std::shared_ptr<T> {
typedef std::shared_ptr<T> super;
public:
inline NonNull()
: super(new T())
{
if ( ! super::get()) {
abort(); // Out of memory.
}
}
inline explicit NonNull(T *ptr)
: super(ptr)
{
if ( ! super::get()) {
abort(); // Input was null.
}
}
}
Basically, forces us to construct the class of T type.
Usage:
// Directly is a `std::shared_ptr` type:
NonNull<MyClass> myVariable;
// Unlike:
gsl::not_null<std::shared_ptr<MyClass > > myVariable;