Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Example code from articles on perfect forwarding to async lambdas. Involves moves, async, templates and perfect forwarding.
PROGS=part1 part2
CC=g++-4.7
CFLAGS= -Wall -Werror -O3 -std=c++0x
LIBS= -lpthread
all: $(PROGS)
%: %.cpp
$(CC) $(CFLAGS) -o $@ $^ $(INC_DIRS:%=-I%) $(LIB_DIRS:%=-L%) $(LIBS)
.PHONY: clean
clean:
rm $(PROGS)
#ifndef MOVE_CHECKER_HPP_12ZK6OPS
#define MOVE_CHECKER_HPP_12ZK6OPS
#include <vector>
#include <utility>
#include <memory>
#include <iostream>
class move_checker
{
// shared counters of copies and moves
std::shared_ptr<int> copies_;
std::shared_ptr<int> moves_;
public:
// expensive payload
std::vector<int> payload;
typedef std::vector<int>::const_iterator const_iterator;
move_checker()
: copies_(new int(0)),
moves_(new int(0)),
payload({1, 2, 3, 4, 5, 6, 7})
{ }
// copy constructor. counts copy operations
move_checker(move_checker const& other)
: copies_(other.copies_),
moves_(other.moves_),
payload(other.payload)
{
*copies_ += 1;
}
// copy assignment
move_checker& operator = (move_checker const& other)
{
copies_ = other.copies_;
moves_ = other.moves_;
payload = other.payload;
*copies_ += 1;
return *this;
}
// move constructor. counts move operations
move_checker(move_checker&& other)
: copies_(other.copies_),
moves_(other.moves_),
payload(std::move(other.payload))
{
*moves_ += 1;
}
// move assignment
move_checker& operator = (move_checker&& other)
{
copies_ = other.copies_;
moves_ = other.moves_;
payload = std::move(other.payload);
*moves_ += 1;
return *this;
}
const_iterator begin() const { return payload.begin(); }
const_iterator end() const { return payload.end(); }
// methods to report on the number of copies/moves
int copies() const { return *copies_; }
int moves() const { return *moves_; }
};
void check_copies(move_checker const& checker, int expected)
{
std::cout << "Copies: " << checker.copies()
<< " (expected " << expected << ")" << std::endl;
}
void check_moves(move_checker const& checker, int expected)
{
std::cout << "Moves: " << checker.moves()
<< " (expected " << expected << ")" << std::endl;
}
#endif /* end of include guard: MOVE_CHECKER_HPP_12ZK6OPS */
#include "move_checker.hpp"
#include <vector>
#include <string>
#include <thread>
#include <future>
#include <iostream>
#include <cassert>
#include <functional>
class vector_holder
{
std::vector<std::string> vec_;
public:
// copy a vector into this object.
vector_holder(std::vector<std::string> const& vec)
: vec_(vec)
{
std::cout << "copied!" << std::endl;
}
// move a vector into this object.
// essentially a transfer of ownership
vector_holder(std::vector<std::string>&& vec)
: vec_(std::move(vec))
{
std::cout << "moved!" << std::endl;
}
// move constructor.
// instead of copying, we transfer
// the internals into this object
vector_holder(vector_holder&& other)
: vec_(std::move(other.vec_))
{ }
};
// prints the contents of an iterable
template <typename Iterable>
void printContents(Iterable const& iterable)
{
for (auto e : iterable)
{
std::cout << e << std::endl;
}
}
void asyncWithRvalue()
{
move_checker checker;
assert( checker.copies() == 0 );
assert( checker.moves() == 0 );
// (hopefully) pass by reference
std::future<void> task =
std::async(
std::launch::async,
printContents<move_checker>,
std::move(checker)
);
// wait for the task to complete
task.wait();
// no copies or moves!
check_copies(checker, 0 );
check_moves(checker, 2 );
}
void asyncWithLvalue()
{
move_checker checker;
assert( checker.copies() == 0 );
assert( checker.moves() == 0 );
// (hopefully) pass by reference
std::future<void> task =
std::async(
std::launch::async,
printContents<move_checker>,
checker
);
// wait for the task to complete
task.wait();
// no copies or moves!
check_copies(checker, 1 );
check_moves(checker, 1 );
}
void asyncWithPointer()
{
move_checker checker;
assert( checker.copies() == 0 );
assert( checker.moves() == 0 );
// Wrap the reference to fool std::async
std::future<void> task =
std::async(
std::launch::async,
printContents<move_checker>,
std::ref(checker)
);
// wait for the task to complete
task.wait();
// no copies or moves!
check_copies(checker, 0 );
check_moves(checker, 0 );
}
int main(int argc, char const *argv[])
{
// lvalue vs rvalue
std::vector<std::string> lvalue{"Hello", "World"};
vector_holder copy_holder(lvalue);
vector_holder move_holder(std::move(lvalue));
asyncWithRvalue();
asyncWithLvalue();
asyncWithPointer();
return 0;
}
#include "move_checker.hpp"
#include <utility>
#include <future>
#include <cassert>
template <typename T> struct async_forwarder;
template <typename T>
class async_forwarder
{
T val_;
public:
async_forwarder(T&& t) : val_(std::move(t)) { }
async_forwarder(async_forwarder const& other) = delete;
async_forwarder(async_forwarder&& other)
: val_(std::move(other.val_)) { }
operator T&& () { return std::move(val_); }
operator T&& () const { return std::move(val_); }
};
template <typename T>
class async_forwarder<T&>
{
T& val_;
public:
async_forwarder(T& t) : val_(t) { }
async_forwarder(async_forwarder const& other) = delete;
async_forwarder(async_forwarder&& other)
: val_(other.val_) { }
operator T& () { return val_; }
operator T const& () const { return val_; }
};
// forward our move_checker to count moves/copies
template <typename T>
int forwardToLambda(T&& checker)
{
auto lambda =
[](T&& checker) mutable
{
return checker.payload[0];
};
return lambda(std::forward<T>(checker));
}
template <typename InputIterable, typename Func>
std::future<void> connect(InputIterable&& input, Func func)
{
return std::async(std::launch::async,
[func](InputIterable&& input) mutable
{
// have to "dereference" our wrapper.
for (auto&& e : input) {
func(e);
}
},
async_forwarder<InputIterable>(std::forward<InputIterable>(input))
);
}
// simply print a value on a separate line
template <typename T>
void printOnLine(T const& val)
{
std::cout << val << std::endl;
}
int main(int argc, char const *argv[])
{
move_checker checker;
assert( checker.copies() == 0 );
assert( checker.moves() == 0 );
forwardToLambda(checker);
// no copies or moves!
assert( checker.copies() == 0 );
assert( checker.moves() == 0 );
auto solutionWithLvalue = connect(checker, printOnLine<int>);
solutionWithLvalue.wait();
assert( checker.copies() == 0 );
assert( checker.moves() == 0 );
auto solutionWithRvalue = connect(std::move(checker), printOnLine<int>);
solutionWithRvalue.wait();
check_copies(checker, 0 );
check_moves(checker, 3 );
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment