Last active
May 2, 2017 06:42
-
-
Save KholdStare/4313633 to your computer and use it in GitHub Desktop.
Example code from articles on perfect forwarding to async lambdas. Involves moves, async, templates and perfect forwarding.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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