copy constructor do not work in cpp template - c++11

I'm writing a test program about c++ type erasure, the code is put on the end.
when I run program , the test case 2 output as follow:
A default cstr...0x7ffe0fe5158f
obj_:0x7ffe0fe5158f objaaa 0x7ffe0fe5158f
Print A 0x7ffe0fe5158f
my machine: Linux x86-64, gcc 4.8
In my opinion, "Object obj2(a2);" makes a class Model by lvalue reference, so it should call A's copy constructor,
but actually it did not work, it makes me confused.
someone can give a explanation, thank you in advance.
the program is list as follow:
#include <memory>
#include <iostream>
class Object {
public:
template <typename T>
Object(T&& obj) : object_(std::make_shared<Model<T>>(std::forward<T>(obj))) {
}
void PrintName() {
object_->PrintName();
}
private:
class Concept {
public:
virtual void PrintName() = 0;
};
template <typename T>
class Model : public Concept {
public:
Model(T&& obj) : obj_(std::forward<T>(obj)) {
std::cout << "obj_:" << std::addressof(obj_) <<" objaaa " << std::addressof(obj) << std::endl;
}
void PrintName() {
obj_.PrintName();
}
private:
T obj_;
};
private:
std::shared_ptr<Concept> object_;
};
class A {
public:
A(A& a) {
std::cout<< "A copy cstr...a" << this << std::endl;
}
A(A&& a) {
std::cout << "A move cstr...." <<this<< std::endl;
}
A() {
std::cout << "A default cstr..." <<this<< std::endl;
}
void PrintName() {
std::cout << "Print A " << this << std::endl;
}
};
int main(void)
{
// test case 1
Object obj{A()};
obj.PrintName();
// test case 2
A a2;
Object obj2(a2);
obj2.PrintName();
return 0;
}

In Object obj2(a2);, no copy is made. T in the constructor of Object is deduced to be A&, so it instantiates Model<A&>, which stores a reference to the original a2 object as its obj_ member.
Observe that in your debug output, a2's constructor, Model's constructor and PrintName all print the same address. You can further confirm that this address is in fact &a2.

Related

Using move semantics to avoid copying when pushing_back to a custom container does not avoid copying

I have implemented a custom container (same vein as std::vector) and I am trying to make it so that its 'push_back' function would use leverage on move semantics to avoid creating a copy of whatever is being pushed back - specially when the object to be pushed into the container is returned by an external function.
After reading quite a bit about move semantics and custom containers, I still can't find why my approach is still generating a copy instead of just moving the passed object into the container's inner dynamic array.
Here is a simplified version of my container looks like:
template<class T>
class Constructor
{
private:
size_t size = 0;
size_t cap = 0;
T *data = nullptr;
public:
Constructor()
{
cap = 1;
size = 0;
data = static_cast<T*>(malloc(cap * sizeof(T)));
}
~Constructor()
{ delete[] data; }
template<typename U>
void push_back(U &&value)
{
if (size + 1 >= cap)
{
size_t new_cap = (cap * 2);
T* new_data = static_cast<T*>(malloc(new_cap * sizeof(T)));
memmove(new_data, data, (size) * sizeof(T));
for (size_t i = 0; i<cap; i++)
{
data[i].~T();
}
delete[] data;
cap = new_cap;
data = new_data;
new(data + size) T(std::forward<U>(value));
}
else
{
new(data + size) T(std::forward<U>(value));
}
++size;
}
const T& operator[](const size_t index) const //access [] overloading
{
return data[index];
}
};
Here is a custom class that will print messages when its instances are created, copied or moved, in order to help debugging:
class MyClass
{
size_t id;
public:
MyClass(const size_t new_id)
{
id = new_id;
std::cout << "new instance with id " << id << std::endl;
}
MyClass(const MyClass &passedEntity)
{
id = passedEntity.id;
std::cout << "copied instance" << std::endl;
}
MyClass(MyClass &&passedEntity)
{
id = passedEntity.id;
std::cout << "moved instance" << std::endl;
}
void printID() const
{
std::cout << "this instance's id is " << id << std::endl;
}
};
And here is the external function:
MyClass &foo(MyClass &passed)
{
return passed;
}
Lastly, here is the main function that runs a test case using the above function and classes to show the problem:
int main()
{
MyClass a(33);
std::cout << std::endl;
std::cout << "Using my custom container: " << std::endl;
Constructor<MyClass> myContainer;
myContainer.push_back(foo(a));
myContainer[0].printID();
std::cout << std::endl;
std::cout << "Using dinamic array: " << std::endl;
MyClass *dinArray = static_cast<MyClass*>(malloc(1 * sizeof(MyClass)));
dinArray = new(dinArray + 1) MyClass(std::forward<MyClass>(foo(a)));
dinArray[0].printID();
std::cout << std::endl;
system("Pause");
return 0;
}
The output is:
new instance with id 33
Using my custom container:
copied instance
this instance's id is 33
Using dinamic array:
moved instance
this instance's id is 33
As it can be seen, if the instance of MyClass is put directly into a dynamic array, then just the move conmstructor is called and not the copy constructor. However, if I push_back the yClass instance into an instance of Container, a copy constructor is still being called.
Could someone help me understand what exactly am I doing wrong here? How could I make it so that elements are pushed into the container without generating a copy?
When you call this line
myContainer.push_back(foo(a));
L-value is passed into push_back method, and now read about using std::forward - http://www.cplusplus.com/reference/utility/forward/,
Returns an rvalue reference to arg if arg is not an lvalue reference.
If arg is an lvalue reference, the function returns arg without modifying its type.
and in your push_back you call
new(data + size) T(std::forward<U>(value));
but value was passed as L-value, and only constructor MyClass(const MyClass &passedEntity) can be invoked.
If you want a object to be moved, you can write
myContainer.push_back(std::move(a)); // cast to R-reference
EDIT
You should not use move in your push_back function, below is simple example.
Suppose you have class like this:
struct Foo {
int i;
Foo (int i = 0) : i(i) {
}
~Foo () {
}
Foo (const Foo& ) {
}
Foo& operator=(const Foo&) {
return *this;
}
Foo (Foo&& f)
{
i = f.i;
f.i = 0; // this is important
}
Foo& operator=(Foo&& f)
{
i = f.i;
f.i = 0; // this is important
return *this;
}
};
we have also 2 functions
template<class T>
void process1 (const T& ) {
cout << "process1" << endl;
}
template<class T>
void process (T&& obj) {
cout << "process2" << endl;
T newObj = forward<T>(obj);
}
and bars functions are counterparts of your push_back method.
template <typename T>
void bar1 (T&& value) {
process (move(value)); // you use move in your push_back method
}
template <typename T>
void bar2 (T&& value) {
process (forward<T>(value));
}
now we must consider 4 cases:
[1] pass L-value, version with forward
Foo f(20);
bar2 (f);
cout << (f.i) << endl; // 20
[2] pass R-value, version with forward
Foo f(20);
bar2 (move(f));
cout << (f.i) << endl; // 0, it is OK bacuse we wanted to move 'f' object
[3] pass R-value, version with move
Foo f(20);
bar1 (move(f));
cout << (f.i) << endl; // 0, ok, we wanted to move 'f' object
[4] pass L-value, version with move in your push_back method
Foo f(20);
bar1 (f);
cout << (f.i) << endl; // 0 !!! is it OK ? WRONG
in last case, we passed f as L-value, but this object was moved in bar1 function, for me this is strange behavior and is incorrect.
It is not safe to perform a memmove with objects in C++.
You can find more information here Will memcpy or memmove cause problems copying classes?
If this is C++11 onwards, then what you want to use is placement new and the move constructor. (you could probably just bin the placement new though unless you really want to keep allocating memory yourself)
If this is any other version of C++ then you'll have to just accept that that either you're going to have to copy the object (like the rest of the stl) or that your object will have to implement a function like void moveTo(T& other)

Understand C++11 solution for checking the existence of a member function

https://stackoverflow.com/a/31860104
#include <iostream>
#include <string>
template<class T>
auto optionalToString(T* obj)
-> decltype( obj->toString() )
{
return obj->toString();
}
auto optionalToString(...) -> std::string
{
return "toString not defined";
}
struct TA
{
std::string toString() const
{
return "Hello";
}
};
struct TB
{
};
Question> Given the proposed solution optionalToString, how I can use it to detect that TA has toString while TB doesn't.
A solution using can_apply from this code:
template<class T>
using toString_result = decltype(std::declval<T>().toString());
template<class T>
constexpr auto has_toString = can_apply<toString_result, T>::value;
Used like this:
struct TA
{
std::string toString() const
{
return "Hello";
}
};
struct TB
{
};
int main()
{
std::cout << has_toString<TA> << '\n';
std::cout << has_toString<TB> << '\n';
return 0;
}
DEMO
The given solution allows you to always get a string from any object. If it has a toString() member function, this will be used, otherwise, a default string. Usage example, given the above:
TA a;
TB b;
std::cout << "a: " << optionalToString(&a) << '\n';
std::cout << "b: " << optionalToString(&b) << std::endl;
However, you will not get a boolean value whether a or b has a toString() method. If you want that, you need something like the solution proposed by O'Neil.

c++11 dedicated "proxy constructors" delegating to private univeral reference constructor?

Reading Scott Meyer's book "Effective Modern C++", Item 24 (and following), and Item 41, I wonder that this book opposes:
the individual constructors for lvalue and rvalue parameters
to
a template'd universal constructor solution
It says, that 1. has the disadvantage to duplicate code.
Whereas 2. has the disadvantage to potentially being used for unwanted types.
I wonder why the book does not mention a mixed model - as in the example code shown below.
It uses type-safe dedicated constructors for lvalue and rvalue but delegates to a single (private) generic implementation for "universal reference".
This avoids unwanted template types of a public "universal reference" constructor.
So is there is anything wrong with the approach below? Something I missed?
#include <iostream>
#include <string>
class MyClass
{
private:
enum class Dummy { Nop = 0 } ;
template <class T>
MyClass(Dummy, T&& data)
: _data(std::forward<T>(data))
{
std::cout << "MyClass universal reference template c'tor" << std::endl;
}
public:
// proxy c'tors delegating to universal reference c'tor
MyClass (std::string const & data)
: MyClass(Dummy::Nop, data)
{
std::cout << "MyClass lvalue c'tor" << std::endl;
}
MyClass (std::string && data)
: MyClass(Dummy::Nop, std::move(data))
{
std::cout << "MyClass rvalue c'tor" << std::endl;
}
private:
std::string _data;
};
int main(int, char**)
{
{
std::string str("demo");
MyClass myClass(str);
}
{
MyClass myClass("hello, world");
}
return 0;
}
And now let's put the book down and do it the right way:
Pros:
Optimal efficiency
Correct type limitations
DRY
Cons:
None
-
#include <iostream>
#include <string>
#include <type_traits>
class MyClass
{
public:
template <class T, std::enable_if_t<std::is_constructible<std::string, T>::value>* = nullptr>
MyClass(T&& data)
: _data(std::forward<T>(data))
{
std::cout << "MyClass universal reference template c'tor" << std::endl;
}
private:
std::string _data;
};
int main()
{
using namespace std::string_literals;
auto a = MyClass("hello"s);
auto b = MyClass("world");
const auto s = "Hello, World"s;
auto s2 = "Hello, World";
auto c = MyClass(s);
auto d = MyClass(s2);
// won't compile
// auto e = MyClass(10);
}

segfault when accessing static std::map

I'm trying to refactor a rather complicated piece of code and run into segfaults during loading the library. This is a minimal example of what I could single out to be the source of the segfault:
#include <iostream>
#include <string>
#include <map>
class Manager {
public:
class Action{
};
static bool registerAction(const Action* a, const char* name);
};
namespace Actions {
class ExampleAction : public Manager::Action {
};
namespace {
static bool available = Manager::registerAction(new ExampleAction(),"ExampleAction");
}
}
namespace {
typedef std::map<const std::string,const Manager::Action*> ActionList;
static ActionList sActions;
}
bool Manager::registerAction(const Action* a, const char* name){
std::cout << "attempting to register action " << a << " as " << name << std::endl;
sActions[name] = a;
std::cout << "done" << std::endl;
return true;
}
int main(){
std::cout << "hello!" << std::endl;
for(auto it:sActions){
std::cout << it.first << std::endl;
}
std::cout << "world!" << std::endl;
return 0;
}
It compiles fine with g++ 4.8.4 using the --std=c++11 flag, but upon execution, this happens:
attempting to register action 0x1ebe010 as ExampleAction
Segmentation fault (core dumped)
The line attempting to register comes first, which is of course expected, but the line assigning the value to the static map instance causes the crash, and I don't understand the reason. I'm probably being stupid here, but still - any suggestions on how to fix this?

What is the best way to pass callback function to std::map?

I was trying to work on the below code but the program crashes:
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef void (*callBackMethod)(string);
class CTest
{
private:
map<string, callBackMethod> mapMethod;
void testMethod(string msg)
{
cout << msg << endl;
}
public:
CTest()
{
addFunction("AA", (callBackMethod) &CTest::testMethod);
}
void addFunction(string funName, callBackMethod methodName)
{
mapMethod[funName] = methodName;
}
callBackMethod getMethod(string funName)
{
auto fun = mapMethod.find(funName);
if(fun == mapMethod.end()) { return nullptr; }
return fun->second;
}
void runFunction(string funName)
{
getMethod(funName)("test");
}
};
int main()
{
CTest test;
test.runFunction("AA");
return 0;
}
I have a requirement where I need to pass private methods to a map. The program compiles with warning:
converting from 'void (CTest::*)(std::__cxx11::string) {aka void (CTest::*)(std::__cxx11::basic_string<char>)}' to 'callBackMethod {aka void (*)(std::__cxx11::basic_string<char>)}'
and when I execute this, it crashes.
When I move the callback method outside of the class it works. My requirement is to make the program flow this was (hide the methods from external call which needs to be added to a map).
Looking forward to your comments.
If you need to point to both CTest member functions and free functions, then you can use std::function<void(std::string)>.
#include <iostream>
#include <string>
#include <map>
#include <functional>
using namespace std;
using callBackFunction = std::function<void(string)>;
void testFunction(string msg)
{
cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl;
}
class CTest
{
private:
map<string, callBackFunction> mapMethod;
void testMethod(string msg)
{
cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl;
}
public:
CTest()
{
addFreeFunction("AA", testFunction);
addMemberFunction("BB", &CTest::testMethod);
}
void addMemberFunction(string funName, void(CTest::*methodName)(string))
{
using std::placeholders::_1;
mapMethod[funName] = std::bind(methodName, this, _1);
}
void addFreeFunction(string funName, void(*methodName)(string))
{
mapMethod[funName] = methodName;
}
callBackFunction getMethod(string funName)
{
auto fun = mapMethod.find(funName);
if(fun == mapMethod.end()) { return nullptr; }
return fun->second;
}
void runFunction(string funName)
{
getMethod(funName)("test");
}
};
int main()
{
CTest test;
test.runFunction("AA");
test.runFunction("BB");
return 0;
}
Notice that CTest must insert elements into the map in a different way depending on what type of function you are passing, since for member functions you must provide the object for which it is to be invoked, this in this example. This is achived by using std::bind.
Since you want to use member variables you need to specify the signature differently in your typedef:
In C++ Builder the following can be done:
typedef void(__closure *callBackMethod)(string);
If you do that, I do suggest that you keep a smart pointer to the object that the member belongs to so that you can check if the object is still valid before calling the function otherwise it will crash the application.
The __closure keyword is a C++ Builder extension to work around the requirement to use fully qualified member names source
To handle both global and member functions we have the following:
typedef void(__closure *callBackMethodMember)(string);
typedef void (*callBackMethodGlobal)(string);
/* And then on 2 overloaded functions */
void addFunction(string funName, callBackMethodMember methodName) {}
void addFunction(string funName, callBackMethodGlobal methodName) {}

Resources