Is there a way where I could move the object GuitarSpec that is created in main instead of it being copied?
So here is the following example:-
There is an Inventory class that has a list of guitars, and to add a guitar, there is a function called addGuitar that takes string, double and GuitarSpec object as an argument.
Inventory
class Inventory {
private:
list<Guitar> inventory;
public:
void addGuitar(const string &, double, const GuitarSpec &spec);
addGuitar function
void Inventory::addGuitar(const string &serialNumber, double price,
const GuitarSpec &spec) {
inventory.emplace_back(serialNumber, price, spec);
}
Guitar Constructor
Guitar::Guitar(const string& serialNumber, double price, const GuitarSpec &spec)
: serialNumber{serialNumber}, price{price}, spec(spec) {
cout << "Guitar Constructor" << endl;
}
Main function:-
Inventory inventory;
inventory.addGuitar(
"1001", 200,
GuitarSpec(toString(FEDER), "starocaster", toString(ELECTRIC),
toString(Wood::SIKTA), toString(Wood::SIKTA)));
Is there a way to move that GuitarSpec object instead of taking a copy of it, or any other better solution?
When you consider moving only one parameter, you might get away with declaring function overloads, one of which would be moving from a temporary. Or you have design where oly temporaries are used, then why don't you follow an "emplace" strategy instead and create new object on-site?
But with two or more parameters moved the number of required overloads would be four, eight and so on. That's not good, in that case perfect forward might be more useful. An example of forwarding single parameter (of type Spec) in C++11 style:
#include <iostream>
#include <utility>
struct Data {
Data(const Data&) { std::cout << "Data copied\n"; }
Data() { std::cout << "Data created\n"; }
};
struct Spec {
Data *ptr;
Spec() : ptr(new Data()) {};
Spec(const Spec& other) : ptr(new Data{*other.ptr}) {};
Spec(Spec && other) : ptr(other.ptr) {
other.ptr = nullptr;
std::cout << "Data moved\n";
}
Spec& operator=(const Spec& other) { ptr = new Data{*other.ptr};
std::cout << "Data copied\n";
return *this; }
Spec& operator=(Spec&& other) { ptr = other.ptr; other.ptr = nullptr;
std::cout << "Data moved\n"; return *this;
}
~Spec() { delete ptr; }
};
struct foo {
Spec d;
template < typename T, std::enable_if_t<std::is_convertible<T, Spec>::value> * = nullptr>
foo(T&& v) : d(std::forward<T>(v)) { }
template <typename T>
auto set_spec(T&& v) -> decltype(v = std::forward<Spec>(v), void())
{ d = std::forward<T>(v); }
};
int main()
{
std::cout << "Move\n";
foo a {Spec()};
a.set_spec(Spec());
std::cout << "Copy\n";
Spec s;
foo b {s};
a.set_spec(s);
}
You have to modify whole chain of responsibility to use that, starting with overloading Inventory's method:
void addGuitar(const string &serialNumber, double price, GuitarSpec&& spec) {
// move, do we want move string?
inventory.emplace_back(serialNumber, price, std::move(spec));
}
Or using perfect forwarding, this template can copy OR move, when appropriate (example without SFINAE):
template <class SN, class SP>
void addGuitar(SN&& serialNumber, double price, SP&& spec)
{
inventory.emplace_back(std::forward<std::string>(serialNumber),
price, std::forward<GuitarSpec>(spec));
}
Technically addGuitar might just be that if we don't want to bother about restricting interface by SFINAE, assuming we would always use it right and nothing wrong may happen (Murphy, put your hand down) if it's not a public interface. A bad assumption in large project with long life and multiple developers.
Related
I am writing a template function which accepts a custom class (that can be any class or primitive type) as a template argument, then reads some data (of that type) from an input stream, and then stores it an unordered map similar to this one:
std::unordered_map<CustomClass, std::vector<CustomClass>> map;
I have implemented a custom class to test the behavior. I have overloaded the std::hash so that this class can be stored in an unordered map as a key and overloaded all operators and constructors such that whenever they are called, I get a message in the console (example, when a copy constructor is called, I get a message "copy constructor [..data...]")
EDIT: As requested in the comments, here is the custom class definition and implementation (please note: the class here is only a placeholder so we can discuss the general idea behind this question. I am well aware that it is dumb and should not be implemented like this. The code for operators >> and << is not here, to avoid clutter)
class CustomClass {
public:
CustomClass(int a=0) {
std::cout << "default constructor" << std::endl;
m_data = a;
}
CustomClass(const CustomClass& other) {
std::cout << "copy constructor " ;//<< std::endl;
m_data = other.m_data;
std::cout << "[" << m_data << "]" << std::endl;
}
CustomClass(CustomClass&& other) {
std::cout << "move cosntructor" << std::endl;
m_data = other.m_data;
}
CustomClass& operator=(const CustomClass& other) {
std::cout << "copy assignment operator" << std::endl;
if(this != &other){
m_data = other.m_data;
}
return *this;
}
CustomClass& operator=(CustomClass&& other) {
std::cout << "move assignment operator" << std::endl;
if(this != &other){
m_data = other.m_data;
}
return *this;
}
~CustomClass() {
std::cout << "destructor" << std::endl;
}
int m_data;
};
Now my question is this: Is it possible to read data from the input stream and construct it inplace where it is needed without a copy constructor call?
Example of some code:
CustomClass x1; // default constructor call
CustomClass x2; // default constructor call
std::cout << "----" << std::endl;
std::cin >> x1 >> x2; // my input
std::cout << "----" << std::endl;
map[x1].emplace_back(x2); // 2 copy constructor calls
std::cout << "----" << std::endl;
std::cout << map[x1][0] << std::endl; // operator== call
std::cout << "----" << std::endl;
And here is an example output from that code:
default constructor
default constructor
----
[1]
[2]
----
copy constructor [1]
copy constructor [2]
----
operator ==
[2]
----
destructor
destructor
destructor
destructor
I would like to have it so that every object of this class is constructed only once.
Is it possible to avoid these copy constructors? If not both, then at least the one that is called during the emplace_back() call? Is it possible to construct the object in the vector exactly where it needs to be in memory but that this sort of call works for every type?
If I need to further elaborate on my question please tell me in the comments, I will be happy to do so
So you have an std::vector and you want to put an element there avoiding unnecessary copying. Assuming that move constructor for your class is cheap, the first option is to define a non-trivial constructor, read the parameters from stream and then emplace_back a newly created object:
using CustomClass = std::vector<int>;
std::vector<CustomClass> v;
size_t size;
int value;
std::cin >> size >> value;
v.emplace_back(size, value);
Here I defined the CustomClass as a vector of integers, and it has a constructor that takes 2 parameters: size and the value. For sure it is cheaper to read there two integers and create the instance of CustomClass only once and using the emplace_back for this purpose, rather than to create the instance and copy it using push_back:
using CustomClass = std::vector<int>;
std::vector<CustomClass> v;
size_t size;
int value;
std::cin >> size >> value;
CustomClass instance(size, value);
v.push_back(instance);
This however doesn't give you much benefits to compare with pushing back the r-value:
using CustomClass = std::vector<int>;
std::vector<CustomClass> v;
size_t size;
int value;
std::cin >> size >> value;
v.push_back(CustomClass(size, value));
Anyway, you need to keep in mind that both push_back and emplace_back may require reallocation of the elements, and that may be inefficient, especially if your CustomClass has no no-throwing move constructor.
Another problem could be if your class doesn't have a reasonable constructor (or the size of the values you need to pass to the constructor are almost the size of the object). In this case I'm offering you the solution to resize() and read to the back()
If the reallocation is something that you are not afraid of (for example you know the number of elements ahead of time and reserve the buffer), you can do the following:
std::vector<CustomClass> v;
v.resize(v.size() + 1);
std::cin >> v.back();
In this case you create a default value once and then read the contents.
Another solution could be to pass the std::istream to the constructor of CustomClass:
class CustomClass {
public:
CustomClass(std::istream&);
};
std::vector<CustomClass> v;
v.emplace_back(cin);
Update:
Assuming that you know nothing about the actual type of the CustomClass, the most generic (not fully generic, as it still requires default constructor to be able to be pushed with resize()) is to use resize()/back() idiom.
This is how you do it (avoids any unnecessary ctor calls, including a default one):
#include <vector>
#include <unordered_map>
#include <cstdio>
#include <iostream>
using namespace std;
//--------------------------------------------------------------------------
template <class F> struct inplacer
{
F f;
operator invoke_result_t<F&>() { return f(); }
};
template <class F> inplacer(F) -> inplacer<F>;
//--------------------------------------------------------------------------
struct S
{
S(istream&) { printf("istream ctor\n" ); }
S() { printf("ctor\n" ); }
~S() { printf("dtor\n" ); }
S(S const&) { printf("cctor\n"); }
S(S&&) { printf("mctor\n"); }
S& operator=(S const&) { printf("cop=\n"); return *this; }
S& operator=(S&&) { printf("mop=\n"); return *this; }
friend bool operator==(S const& l, S const& r) { return &l == &r; } //!! naturally, this needs proper implementation
};
template<> struct std::hash<S>
{
size_t operator()(S const&) const noexcept { return 0; } //!! naturally, this needs proper implementation
};
//--------------------------------------------------------------------------
template<class R> struct read_impl; // "enables" partial specialization
template<class R> R read(istream& is)
{
return read_impl<R>::call(is);
}
template<> struct read_impl<S>
{
static auto call(istream& is) { return S(is); }
};
template<class T> struct read_impl<vector<T>>
{
static auto call(istream& is)
{
vector<T> r; r.reserve(2); //!! naturally you'd read smth like length from 'is'
for(int i = 0; i < 2; ++i)
r.emplace_back(inplacer{[&]{ return read<T>(is); }});
return r;
}
};
template<class K, class V> struct read_impl<unordered_map<K, V>>
{
static auto call(istream& is)
{
unordered_map<K, V> r;
r.emplace( inplacer{[&]{ return read<K>(is); }}, inplacer{[&]{ return read<V>(is); }} );
return r;
}
};
//--------------------------------------------------------------------------
auto m = read<unordered_map<S, vector<S>>>(cin);
As you can see in the output -- you end up with 3 "istream ctor" calls and 3 "dtor" calls.
As for iostreams -- stay away from them if you care about performance, clarity, etc... The most ridiculous library ever.
P.S. "Partial specialization for function templates" trick is stolen from here.
Here is the problem I was thinking about lately. Let's say our interface is a member function that returns object which is expensive to copy and cheap to move (std::string, std::vector, et cetera). Some implementations may compute the result and return a temporary object while others may simply return a member object.
Sample code to illustrate:
// assume the interface is: Vec foo() const
// Vec is cheap to move but expensive to copy
struct RetMember {
Vec foo() const { return m_data; }
Vec m_data;
// some other code
}
struct RetLocal {
Vec foo() const {
Vec local = /*some computation*/;
return local;
}
};
There are also various "clients". Some only read the data, some require an ownership.
void only_reads(const Vec&) { /* some code */ }
void requires_ownership(Vec) { /* some code */ }
Code above composes well, but is not as efficient as it could be. Here are all combinations:
RetMember retmem;
RetLocal retloc;
only_reads(retmem.foo()); // unnecessary copy, bad
only_reads(retloc.foo()); // no copy, good
requires_ownership(retmem.foo()); // copy, good
requires_ownership(retloc.foo()); // no copy, good
What is a good way to fix this situation?
I came up with two ways, but I'm sure there is a better solution.
In my first attempt I wrote a DelayedCopy wrapper that holds either a value of T or a pointer to const T. It is very ugly, requires extra effort, introduces redundant moves, gets in the way of copy elision and probably has many other problems.
My second thought was a continuation-passing style, which works quite well but turns member functions into member function templates. I know, there is std::function, but it has its overhead so performance-wise it may be unacceptable.
Sample code:
#include <boost/variant/variant.hpp>
#include <cstdio>
#include <iostream>
#include <type_traits>
struct Noisy {
Noisy() = default;
Noisy(const Noisy &) { std::puts("Noisy: copy ctor"); }
Noisy(Noisy &&) { std::puts("Noisy: move ctor"); }
Noisy &operator=(const Noisy &) {
std::puts("Noisy: copy assign");
return *this;
}
Noisy &operator=(Noisy &&) {
std::puts("Noisy: move assign");
return *this;
}
};
template <typename T> struct Borrowed {
explicit Borrowed(const T *ptr) : data_(ptr) {}
const T *get() const { return data_; }
private:
const T *data_;
};
template <typename T> struct DelayedCopy {
private:
using Ptr = Borrowed<T>;
boost::variant<Ptr, T> data_;
static_assert(std::is_move_constructible<T>::value, "");
static_assert(std::is_copy_constructible<T>::value, "");
public:
DelayedCopy() = delete;
DelayedCopy(const DelayedCopy &) = delete;
DelayedCopy &operator=(const DelayedCopy &) = delete;
DelayedCopy(DelayedCopy &&) = default;
DelayedCopy &operator=(DelayedCopy &&) = default;
DelayedCopy(T &&value) : data_(std::move(value)) {}
DelayedCopy(const T &cref) : data_(Borrowed<T>(&cref)) {}
const T &ref() const { return boost::apply_visitor(RefVisitor(), data_); }
friend T take_ownership(DelayedCopy &&cow) {
return boost::apply_visitor(TakeOwnershipVisitor(), cow.data_);
}
private:
struct RefVisitor : public boost::static_visitor<const T &> {
const T &operator()(Borrowed<T> ptr) const { return *ptr.get(); }
const T &operator()(const T &ref) const { return ref; }
};
struct TakeOwnershipVisitor : public boost::static_visitor<T> {
T operator()(Borrowed<T> ptr) const { return T(*ptr.get()); }
T operator()(T &ref) const { return T(std::move(ref)); }
};
};
struct Bar {
Noisy data_;
auto fl() -> DelayedCopy<Noisy> { return Noisy(); }
auto fm() -> DelayedCopy<Noisy> { return data_; }
template <typename Fn> void cpsl(Fn fn) { fn(Noisy()); }
template <typename Fn> void cpsm(Fn fn) { fn(data_); }
};
static void client_observes(const Noisy &) { std::puts(__func__); }
static void client_requires_ownership(Noisy) { std::puts(__func__); }
int main() {
Bar a;
std::puts("DelayedCopy:");
auto afl = a.fl();
auto afm = a.fm();
client_observes(afl.ref());
client_observes(afm.ref());
client_requires_ownership(take_ownership(a.fl()));
client_requires_ownership(take_ownership(a.fm()));
std::puts("\nCPS:");
a.cpsl(client_observes);
a.cpsm(client_observes);
a.cpsl(client_requires_ownership);
a.cpsm(client_requires_ownership);
}
Output:
DelayedCopy:
Noisy: move ctor
client_observes
client_observes
Noisy: move ctor
Noisy: move ctor
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
CPS:
client_observes
client_observes
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
Are there better techniques to pass values that avoid extra copies yet are still general (allow returning both temporaries and data members)?
On a side note: the code was compiled with g++ 5.2 and clang 3.7 in C++11. In C++14 and C++1z DelayedCopy doesn't compile and I'm not sure whether it's my fault or not.
There are probably thousands of 'correct' ways. I would favour one in which:
the the method that delivers the reference or moved object is explicitly stated so no-one is in any doubt.
as little code to maintain as possible.
all code combination compile and do sensible things.
something like this (contrived) example:
#include <iostream>
#include <string>
#include <boost/optional.hpp>
// an object that produces (for example) strings
struct universal_producer
{
void produce(std::string s)
{
_current = std::move(s);
// perhaps signal clients that there is something to take here?
}
// allows a consumer to see the string but does not relinquish ownership
const std::string& peek() const {
// will throw an exception if there is nothing to take
return _current.value();
}
// removes the string from the producer and hands it to the consumer
std::string take() // not const
{
std::string result = std::move(_current.value());
_current = boost::none;
return result;
}
boost::optional<std::string> _current;
};
using namespace std;
// prints a string by reference
void say_reference(const std::string& s)
{
cout << s << endl;
}
// prints a string after taking ownership or a copy depending on the call context
void say_copy(std::string s)
{
cout << s << endl;
}
auto main() -> int
{
universal_producer producer;
producer.produce("Hello, World!");
// print by reference
say_reference(producer.peek());
// print a copy but don't take ownership
say_copy(producer.peek());
// take ownership and print
say_copy(producer.take());
// producer now has no string. next peek or take will cause an exception
try {
say_reference(producer.peek());
}
catch(const std::exception& e)
{
cout << "exception: " << e.what() << endl;
}
return 0;
}
expected output:
Hello, World!
Hello, World!
Hello, World!
exception: Attempted to access the value of an uninitialized optional object.
I've hit a wall concerning this explicit copy constructor issue. I've been writing a class to figure things out:
#include <iostream>
template<class T>
class Mat
{
private:
T data;
public:
void set(T value)
{
data = value;
}
Mat()
: data(T(0))
{
}
explicit Mat(const Mat& another)
{
*this = another;
}
Mat& operator=(const Mat& another)
{
data = another.data;
return *this;
}
template<class U>
explicit operator Mat<U>()
{
Mat<U> result;
result.set(static_cast<U>(data));
return result;
}
void print()
{
std::cout << data << std::endl;
}
};
int main()
{
Mat< double > d1;
d1.set(3.14159);
Mat< int > i1(static_cast<Mat<int>>(d1));
d1.print();
i1.print();
std::cin.sync();
std::cin.ignore();
return 0;
}
I want my copy constructor to take only explicitly converted instances of another object, so I declared it explicit, but now I get the error error "C2558: class 'Mat' : no copy constructor available or copy constructor is declared 'explicit'", even though I made an explicit cast:
static_cast<Mat<int>>(d1)
I've declared the copy constructor explicit because I want this to be illegal:
Mat<float> a;
Mat<int> b(a);
While, I would like the following to remain legal:
Mat<float> a;
Mat<int> b(static_cast<Mat<int>>(a));
EDIT: I've been tinkering with this concepts trying to define exactly what I want to get, and I seem to get some funny results:
#include <iostream>
class MatB
{
private:
float data;
public:
MatB()
:data(0.0f)
{
}
void set(float value)
{
data = value;
}
float getData() const
{
return data;
}
void print()
{
std::cout << data << std::endl;
}
};
class MatA
{
private:
double data;
public:
MatA()
:data(0.0)
{
}
void set(double value)
{
data = value;
}
double getData() const
{
return data;
}
explicit operator MatB()
{
MatB temp;
temp.set(static_cast<float>(getData()));
return temp;
}
void print()
{
std::cout << data << std::endl;
}
};
class MatC
{
private:
int data;
public:
MatC()
:data(0)
{
}
explicit MatC(const MatB& in)
:data(static_cast<int>(in.getData()))
{
}
void print()
{
std::cout << data << std::endl;
}
};
int main()
{
MatA someA;
someA.set(3.14159);
MatC constructCFromA(someA);
someA.print();
constructCFromA.print();
std::cin.sync();
std::cin.ignore();
return 0;
}
In this example, constructCFromA(someA) shouldn't compile (imo) - even the linker marks it as an error(VS2013), still it compiles just fine... I am not sure whether my understanding of 'explicit' is incorrect, whether the IDE marks it as an error incorrectly, or the compiler compiles it even though it shouldn't. I thought I would need to do something like this:
constructCFromA(static_cast<MatB>(someA));
The IDE seems to agree with me, but the compiler doesn't. I must say I am pretty confused.
EDIT2:
Never mind, in Ideone it doesn't compile, so I guess MS are to blame.
I think the 2nd code illustrates well the behaviour I want to get. Basically make non-explicit conversions at initialization and assignment illegal. It seems however, that making the copy constructor explicit has various "side-effects".
The line where you did the explicit cast is not a problem. The problem that causes the compiling issue is on the line where you return Mat<U> by value:
template<class U>
explicit operator Mat<U>()
{
Mat<U> result;
result.set(static_cast<U>(data));
return result; // <<== This line requires a copy constructor to be defined
}
That is why when you remove explicit before the copy ctor, your code works just fine.
here's another version that will pass your unit test without the need for a conversion operator to T:
template<class T>
class Mat
{
private:
T data;
public:
void set(T value)
{
data = value;
}
// default constructor
Mat()
: data(T(0))
{
}
// construct from data type
explicit Mat(T dat)
: data(dat)
{}
// construct from any compatible Mat
template<class U>
explicit Mat(const Mat<U>& another)
: data(static_cast<T>(another.get_data()))
{}
// assign from any compatible Mat
template<class U>
Mat& operator=(const Mat<U>& another)
{
data = static_cast<T>(another.get_data());
return *this;
}
// provide a means to access data from unrelated Mat
const T& get_data() const { return data; }
void print()
{
std::cout << data << std::endl;
}
};
I'm trying to write a class that accepts a a function pointer AND/OR a functor to be user later by the class.
To illustrate better what I'd like to do:
template <typename T> class Holder {
private:
T *m_ptr;
<something> m_func;
public:
Holder(T *ptr) : m_ptr(ptr), m_func(NULL) {
}
Holder(T *ptr, <something> func) : m_ptr(ptr), m_func(func) {
}
~Holder() {
if (m_func) {
m_func(m_ptr);
} else {
delete m_ptr;
}
}
};
Considering I'd like to handler objects of this type:
class MyClass {
public:
void describe() {
cout << "Bla bla bla ...";
}
};
Then I could use it this way:
class MyClassFunctor {
public:
void operator()(MyClass *ptr) const {
cout << "Deleting ptr using functor: ";
ptr->describe();
cout << endl;
delete ptr;
}
};
int main() {
MyClass *myclass = new MyClass();
MyClassFunctor functor();
{
Holder<MyClass> holder(myClass, functor);
}
cout << "I'm out of context now!" << endl;
}
AND (not or) this way:
void myClassDeleter(MyClass *ptr) {
cout << "Deleting ptr using function pointer: ";
ptr->describe();
cout << endl;
delete ptr;
}
int main() {
MyClass *myclass = new MyClass();
{
Holder<MyClass> holder(myClass, &myClassDeleter);
}
cout << "I'm out of context now!" << endl;
}
Notice I'd like to be able to use both approaches: Functors AND function pointers.
I'd say it is possible, since this is what Boost::shared ptr and tr1::shared_ptr does.
I tried digging into Boost::shared_ptr code, but I couldn't really understand how they do it.
I'm sorry if my code is wrong or seems to be naive. I tried to explain the problem as concisely as possible, so code correctness wasn't my main focus here (I realize this is important).
Notice I don't even think about rewriting a smart pointer class from scratch. This is out of question here, since I know it is not a wise call.
I'm interested in knowing how to do it so I can use this mechanism for other purposes. Smart pointers were simply the simplest use of that I could remember.
For now, I'd like to avoid using boost and C++11. Is it possible to do it using plain c++03?
Thanks very much for your time.
The answer is: Type Erasure.
The implementation is not that simple, and I suggest reading about Type Erasure a little (as I just did!).
First of all, you need to create the Type Erased apparatus:
class ActionBase {
public:
virtual ~ActionBase() { }
virtual bool DoIt() = 0;
};
template<typename P>
class ActionP : public ActionBase {
private:
P *ptr;
public:
ActionP(P *p) : ptr(p) { }
virtual bool DoIt() {
cout << "Standard action (nothing to do)..." << endl;
return true;
}
};
template<typename P, class A>
class ActionPA : public ActionBase {
private:
P *ptr;
A action;
public:
ActionPA(P *p, A & a ) : ptr(p), action(a) { }
virtual bool DoIt() { return action(ptr); }
};
Then you can declare the Holder class:
template<typename T>
class Holder {
private:
// Avoid object copy and assignment.
Holder(const Holder<T> &rhs);
Holder<T>& operator=(const Holder<T> &rhs);
protected:
T* ptr;
ActionBase *action;
public:
template<typename U> Holder(U *ptr) : ptr(ptr), action(new ActionP<U>(ptr)) { }
template<typename U, class A> Holder(U* p, A a) : ptr(p), action(new ActionPA<U, A>(p, a)) { }
virtual ~Holder() { delete ptr; delete action; }
bool DoAction() {
return this->action->DoIt();
}
};
Then you can use it passing function pointers, functors, or even nothing:
template<typename T>
class ActionFunctor {
public:
bool operator()(T* instance) const {
cout << "Action operator..." << endl;
// Simple operation: set the value to 3 times the original value (works for int and string!!)
instance->Set(instance->Get() + instance->Get());
return true;
}
};
template<typename T>
bool ActionFunc(T* instance) {
cout << "Action function..." << endl;
// Simple operation: set the value to 3 times the original value (works for int and string!!)
instance->Set(instance->Get() + instance->Get() + instance->Get());
return true;
}
int main() {
{
cout << "First test:" << endl;
ActionFunctor<X> actionX;
Holder<X> x1(new X(1), &ActionFunc<X>);
Holder<X> x2(new X(10), actionX);
Holder<X> x3(new X(100));
x1.DoAction();
x2.DoAction();
x3.DoAction();
}
{
cout << "Second test:" << endl;
ActionFunctor<Y> actionY;
Holder<Y> y1(new Y("A"), &ActionFunc<Y>);
Holder<Y> y2(new Y("BB"), actionY);
Holder<Y> y3(new Y("CCC"));
y1.DoAction();
y2.DoAction();
y3.DoAction();
}
return 0;
}
Here is the output:
First test:
X constructor: 1
X constructor: 10
X constructor: 100
Action function...
Action operator...
Standard action (nothing to do)...
X desstructor: 100
X desstructor: 20
X desstructor: 3
Second test:
Y constructor: "A"
Y constructor: "BB"
Y constructor: "CCC"
Action function...
Action operator...
Standard action (nothing to do)...
Y destructor: "CCC" ...
Y destructor: "BBBB" ...
Y destructor: "AAA" ...
Hope it's useful for someone else.
One obvious solution is to use boost::function or std::function. However, if you want to avoid the overhead these objects add, you can make Holder to accept a Callable as a template argument:
template <typename T, class F>
class Holder
{
private:
T *m_ptr;
F m_func;
//...
Of course, you'd have to make a helper function that would deduct the actual type of the Callable:
// depending on the nature of your functors, consider passing by const &
template<typename T, class F>
Holder<T, F> make_holder(T *t, F f)
{
return Holder<T, F>(t, f);
}
Use it like this:
auto holder = make_holder(myClass, &myClassDeleter);
// or:
auto holder = make_holder(myClass, functor);
I need to create a generic object carrier class. I came up with something simple like
template<typename T>
class ObjectCarrier
{
public:
const T& item() const
{
return item_;
}
void setItem(T& item)
{
item_ = item;
}
private:
T item_;
};
This works well when T has got a default constructor (parameterless). Things gets complicated when T has parameterized constructors. So I rewrote the class like
template<typename T>
class ObjectCarrier
{
public:
const T& item() const
{
return *item_;
}
void setItem(T& item)
{
item_ = new T ( item );
}
private:
T* item_;
};
Changed the item_ variable to T* and created a new instance using the copy constructor of T. Again this worked well until T is a pointer type. I mean ObjectCarrier<Foo*> won't work.
I am wondering how can I design this class so that it works for almost all kind of types. I think I may need to create a traits type specialized for pointers. But unfortunately, I am not able to make that work.
Any help would be great.
The above approaches are way way too complicated. Keep it simple, and just solve the constructor arg problem by using template constructors. Don't use pointers, they will create object lifetime and copying headaches.
Here's an implementation I use a lot. The template constructors will forward arguments for things directly on to the nested object which is convenient. The operator T& values let you pass carrier<T> to functions that take a type T, without expensive copying. You can wrap objects that take up to two arguments with this code.
/* A wrapper of type T */
template <typename T>
struct carrier {
carrier() {}
template <typename A1> carrier(const A1& a1) : value(a1) {}
template <typename A1, typename A2> carrier(const A1& a1, const A2& a2) : value(a1, a2) {}
operator T&() { return value; }
operator const T&() const { return value; }
T value;
};
You can use it like this:
const carrier<point> p1(10,10); // make p1 const to stop people changing it
showPoint(p1); // calls a function that expects a point,
showPoint(p1.value); // access the point directly
You can use template specialization for the T* type and rewrite the methods to suite pointers. You can do something like:
template<typename T>
class ObjectCarrier<T*>
{
public:
const T* item() const
{
return item_;
}
void setItem(T* item)
{
item_ = item;
}
private:
T* item_;
};
There is a design patern that is possibly relevant to this - Memento.
A bit off topic, but bear in mind that as soon as you start newing objects up inside your class, you'll need a way to manage the memory. I'd suggest using an std::auto_ptr at the least. You'll also need to provide a copy constructor and an assignment operator, when using std::auto_ptr.
It might be possible to hold the object by value and still defer its construction with the use of placement new and something like the following:
#include <iostream>
#include <cassert>
template <class T>
class ObjectCarrier
{
public:
ObjectCarrier(): ref(0) {}
ObjectCarrier(const ObjectCarrier& other): ref(0)
{
set_data(other.ref);
}
~ObjectCarrier()
{
clear();
}
const ObjectCarrier& operator = (const ObjectCarrier& other)
{
if (other.empty())
clear();
else
set_data(other.ref);
return *this;
}
void set(const T& value)
{
set_value(value);
}
const T& get() const
{
assert(!empty() && "No object being carried");
return *ref;
}
bool empty() const
{
return ref == 0;
}
void clear()
{
if (!empty()) {
ref->~T();
ref = 0;
}
}
private:
char data[sizeof(T)];
T* ref;
void set_value(const T& value)
{
if (!empty()) {
*ref = value;
}
else {
ref = new (data) T(value);
}
}
void set_data(const T* value)
{
if (value) {
set_value(*value);
}
}
};
int main()
{
ObjectCarrier<int> i;
ObjectCarrier<int> j(i);
i = j;
i.set(10);
std::cout << i.get() << '\n';
j = i;
i.set(20);
std::cout << i.get() << ' ' << j.get() << ' ' << ObjectCarrier<int>(i).get() << '\n';
}
However, I would somewhat question the usefulness of this class. Perhaps the only purpose it could have, would be to act as Boost.Optional.
But if you don't want the class to be able to not hold a value, just give it a parametrized constructor:
template<typename T>
class ObjectCarrier
{
public:
ObjectCarrier(const T& value = T()):
item_(value)
{
}
const T& item() const
{
return item_;
}
void setItem(T& item)
{
item_ = item;
}
private:
T item_;
};
(It's just that this class seems rather useless, unless perhaps as a facade for code that expects variables to have item and setItem methods, rather than, say, an assignment operator.)
boost::optional does something very similar to this (also boost::any, but nevermind).
You can check out how its implemented at: http://cplusplus.co.il/2009/12/04/boost-optional-and-its-internals/ and don't worry - it's pretty straightforward.