I'm trying to write a program for my Arduino, but I don't understand something that's happening when passing an Item object to another Holder object. I've constructed a simple example:
class Item {
public:
int property;
Item() {
Serial.println("parameterless constructor called");
this->property = 2;
}
Item(int property) {
this->property = property;
Serial.println("right constructor called");
}
};
class Holder {
public:
Item someitem;
Holder(Item& someitem) {
this->someitem = someitem;
}
};
void setup() {
Serial.begin(9600);
Item someitem = Item(1);
Serial.println(someitem.property);
Holder hold = Holder(someitem);
Serial.println(hold.someitem.property);
}
void loop() {
}
The output on the console is:
right constructor called
1
parameterless constructor called
1
I don't understand why the parameterless constructor is called in the first place (I'm not creating a new object to my understanding), and also why it does neither change the current object nor makes a new one. Leaving out the parameterless constructor is prevented by the compiler.
You forgot how we initialize class members in C++ - member initializer lists:
Holder(Item const& someitem) : someitem(someitem) {}
In your code, someitem is default-constructed first (before execution enters the {} block of the constructor), then you're using assignment operator.
Copy constructor is not invoked (and it can't be on already constructed object).
Related
I have a member variable that is a class that prohibits copying (copy assignment operator is deleted). I want to make some checks to determine what to initiate the member to, thus I need to do this inside the constructor and not in and initializer list. It seem the member variable m is already initialed with the default constructor before entering the constructor of MyClass, then what is the point of the constructor... sorry for c++ rant.
Simple example:
class MyClass {
NonCopy m;
MyClass() {
// Complex checks
if(success) {
m("success");
else {
m("failure");
}
}
The options I see is:
Reside to dynamic allocation of m
Relax copy prohibit requirement of m
As long as the class has a valid copy or move constructor, or you are using C++17+, you can make a helper function that does the logic and then returns the correct object. You then use that to initialize your member. That would look like
class MyClass {
NonCopy m;
static NonCopy initialize_noncopy()
{
// Complex checks
if(success) {
return NonCopy("success");
else {
return NonCopy("faulure");
}
}
public:
MyClass() : m(initialize_noncopy()) { }
};
Well, you're supposed to initialize member variables before the constructor body
struct C {
M member;
C() : member("some arguments") { }
};
But this only works if you know the arguments for the member's initializer at that time! If you really don't want to initialize member until you get some more information in the constructor body, you can place it into a single-member anonymous union.
struct C {
union { M member; };
C() { // member is not initialized
// do whatever
new(&member) M("some arguments"); // explicitly initialize
}
// now you have to write all the other special functions!
~C() { member.~M(); }
C(C const &x) = delete;
C(C &&x) { new(&member) M(std::move(x.member)); }
C &operator=(C const &x) = delete;
C &operator=(C &&x) { member = std::move(x.member); return *this; }
};
Probably I was not clear
class Class {
int member;
otherClass otherClass_member;
Class() { ... }
Class(int x) { ... }
Class(const Class &other) { ... }
Class(Class &&other) : member(other.member), otherClass_member(std::move(other.otherClass_member)) {
member=other.member;
otherClass_member=std::move(other.otherClass_member);
other.member=0;
//other.otherClass_member = ???;
}
~Class() { ... }
I have 3 questions:
what do this do member(other.member), otherClass_member(std::move(other.otherClass_member))?
does it need this member=other.member; otherClass_member=std::move(other.otherClass_member);? I'm asking that because some tutorials put and some don't.
if I have the code above, how should I treat this string other.otherClass_member = ???;
what do this do member(other.member),
otherClass_member(std::move(other.otherClass_member))?
These initialize members of the object you are constructing. Using std::move() allows to steal resources of the existing object other if otherClass has move constructor.
does it need this member=other.member;
otherClass_member=std::move(other.otherClass_member);?
Not only does not it need this, but it would be a mistake because you would be moveing other.otherClass_member twice. You could have these statements instead of the above initialization, but this is an inferior choice and only possible if otherClass has a default constructor.
if I have the code above, how should I treat this string
other.otherClass_member = ???;
You don't need it at all. Move constructor of otherClass should handle this (or copy constructor if move constructor does not exist).
I have a class template in which there is a function that takes an argument of the type of the class that inherits the template. I can't seem to find the right syntax to bring this about. For example, if this is my template:
// A template to promote a simple C-style struct, T_C,
// to a C++ class 'T' with constructors, destructors,
// copy and move assignment operators.
template <typename T_C> class myTemplate
{
// We could in principle create templated copy and move
// constructors and assignment operators, but they'd be
// implicitly deleted by the compiler unless we explicitly defaulted
// them: see
// http://stackoverflow.com/questions/25246573/copy-assignment-operator-defined-in-template-being-deleted-by-compiler.
// Explicitly defaulting them works well if the template is
// contained in an all-header library. However, on including
// the template-derived classes into a DLL in Visual Studio 2013
// it was found that, even when all the other methods
// in a class were properly exported, the defaulted
// template methods were not. There may be a workaround for
// this, but in the scheme of things it was thought easier
// just to dispense with the templated operators and to
// create copy and move assignment operators, as well as the
// corresponding constructors, for each derived type.
//
// We can at least simplify things a little, and force some
// consistency upon our various class definitions,
// by insisting that every relevant class defines the
// functions listed, which can then be called from the
// constructors and assignment operators to make them a bit
// more manageable.
// Tidy up all pointers etc. and return all buffers to a safe state
virtual void clear() = 0;
protected:
// Construct a 'T' from a T_C:
virtual void construct_contents(const T_C &source) = 0;
// Deep copy the contents of a T_C to a 'T'
virtual void copy_contents(const T_C &source) = 0;
// Move the contents of one object to another: for use in both the move constructor
// and the move assignment operator:
virtual void move_contents(myTemplate<T_C> &&source) = 0;
// For sure this is wrong, but I can't figure out
// what the right argument type should be
};
...and this is my class
class myClass : public myStruct, public myTemplate<myStruct>
{
public:
// Default constructor
myClass() {}
// Copy constructor taking basic C struct
myClass(const myStruct &source)
{ construct_contents(source); }
// Copy constructor taking this promoted C++ class
myClass(const myClass &source)
{ construct_contents(source); }
// Copy assignment operator taking basic C struct
MyClass & operator=(const myStruct &source)
{
copy_contents(source);
return *this;
}
// Copy assignment operator taking this promoted C++ class
MyClass & operator=(const myClass &source)
{
copy_contents(source);
return *this;
}
// Move constructor taking this promoted C++ class
myClass(myClass &&source)
{
move_contents(std::move(source));
}
// Move assignment operator taking this promoted C++ class
myClass & operator=(myClass &&source)
{
if (this != &source)
{
clear();
move_contents(std::move(source));
}
return *this;
}
// Destructor
~myClass()
{
clear();
}
// Various getters and setters for the data fields of myStruct
// ....
virtual void clear() override
{
// Stuff...
}
protected:
virtual void construct_contents(const myStruct &source) override
{
// Stuff...
}
virtual void copy_contents(const myStruct &source) override
{
// Stuff...
}
virtual void move_contents(myClass &&source) override
{
// Stuff...
}
};
...then everything works just fine except that the compiler throws an error saying (in Visual Studio 2013) 'member function declared with "override" does not override a base class member' when it encounters my definition of myClass::move_contents. I can understand why it is unhappy: 'myClass' is not only a 'myTemplate<myStruct>', but a type that jointly inherits both myTemplate<myStruct> and myStruct. What I actually need to do is to declare move_contents in the template so that the argument type is the same as the type of the derived object, in this case 'myClass'. However, I can't think of a way of specifying this in the template declaration.
My working solution is to take move_contents out of the template altogether and define a totally independent move_contents method for each separate derived type. This is all right, but doing this would block off the possibilty of pulling the move constructor and assignment operator back into the template - something I'd love to do if I can ever figure out a way of getting Visual Studio 2013 to export them properly.
The template parameter is myStruct, so the method expects an argument of type myTemplate<myStruct>, not myClass.
Declare your method with :
virtual void move_contents(myTemplate<myStruct> &&source) override
{
// Stuff...
}
I'm going to accept #quantdev's answer because he put me on the right track, but here is what eventually worked.
In my original code snippet (see my question above), I inserted an additional public virtual function into the template:
virtual T_C * baseObject() = 0;
In my definition of myClass, I overrode this as follows:
virtual myStruct * baseObject() override { return static_cast<myStruct *>(this); }
This worked because myClass inherits myStruct, so the 'this' pointer of any myClass object is always castable to a myStruct*.
Then, in my move_contents method, I was able to access the myStruct pointers to both the source and destination objects:
void move_contents(myTemplate<myStruct> && source) override
{
stuff = source.baseObject() -> stuff;
source.baseObject() -> stuff = nullptr;
// So that the buffer which my new object now
// points to isn't released when the source
// object is destroyed
}
As far as I can see, this does everything that I need.
#include <iostream>
#include <string.h>
using namespace std;
class withCC
{
public:
withCC() {}
withCC(const withCC&) {
cout<<"withCC(withCC&)"<<endl;
}
};
class woCC
{
enum {bsz = 100};
char buf[bsz];
public:
woCC(const char* msg = 0) {
memset(buf, 0, bsz);
if(msg) strncpy(buf, msg, bsz);
}
void print(const char* msg = 0)const {
if(msg) cout<<msg<<":";
cout<<buf<<endl;
}
};
class composite
{
withCC WITHCC;
woCC WOCC;
public:
composite() : WOCC("composite()") {}
void print(const char* msg = 0) {
cout<<"in composite:"<<endl;
WOCC.print(msg);
}
};
int main()
{
composite c;
c.print("contents of c");
cout<<"calling composite copy-constructor"<<endl;
composite c2 = c;
c2.print("contents of c2");
}
The running result is below:
$ ./a.out
in composite:
contents of c:composite()
calling composite copy-constructor
withCC(withCC&)
in composite:
contents of c2:composite()
And I don't understand why withCC(withCC&) is given as part of output. I guess composite c2 = c; causes copy-constructor to be executed. But as below shown, WITHCC is part of class composite, why it will be invoked to handle this copy-constructor? Thanks!
The copy constructor withCC(withCC&) was invoked because the default copy constructor of composite will call all copy constructors of it's member data. And since you have a withCC object as a member data in the composite class, the copy constructor withCC(withCC&) is called.
Copy constructor is called
When instantiating one object and initializing it with values from another object or
When ever you pass an object by value as an argument to a function or
return the object by value from the function
The default copy constructor of composite class will call the copy constructor of its members, that's why withCC(withCC&) is getting printed.
statement composite c2 = c;
will try to copy the object through copy constructor but class composite does not have user defined copy constructor hence default copy constructor of compiler will be used in your case.
And you want to construct WOCC object also with the creation of composite hence for WOCC construction the user define copy constructor of with cc gets called
I have some class(Window) without copy constructor (it's private). I can't understand how to init var of this class in my own class:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
void init()
{
obj = Window(/* constructor params */); // [error]
obj(/* constructor params */); // [error]
}
}
Error 1: initializing argument 1 of ‘Window::Window(WindowHandle, const sf::WindowSettings&)’
Error 2: ‘NonCopyable& NonCopyable::operator=(const NonCopyable&)’ is private
But it works in this way:
Window obj(/* constructor params */);
Use an initializer list:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass() :
obj(/* constructor params */)
{
}
}
This goes for references, too. You can assign any member variable in an initializer list. It only works in the constructor, though.
If you want it to work outside a constructor, you need to use a pointer:
class MyClass
{
Window *obj;
public:
void init()
{
obj = new Window(/* constructor params */);
}
}
Be sure to deallocate obj using delete in your deconstructor (and make the deconstructor virtual if necessary).
Your MyClass needs a constructor to initialize the obj member.
class MyClass
{
private:
Window obj;
public:
MyClass() : obj(/* constructor params */) // This is an initializer list
{}
};
If you need the init() function, and the Window object provides its own
init() function of some sort, you can do this:
class MyClass
{
private:
Window obj;
public:
void init()
{
obj.init(/* init params */); // Window's own init() function
}
};
If the Window class does not have anything like an init() function, you can use the heap (not recommended unless you absolutely have to):
class MyClass
{
private:
// Alternatively, we can use a smart pointer here and avoid
// managing memory ourselves.
Window* obj;
public:
MyClass() : obj(0) {}
~MyClass() { uninit(); }
void init()
{
uninit();
obj = new Window(/* constructor params */);
}
void uninit()
{
if(obj != 0)
{
delete obj;
obj = 0;
}
}
};
If the Window class declares a private copy constructor and/or copy assignment operator, then you cannot assign a new Window instance to obj.
If your copy constructor is private the class does have a copy constructor. It seems your class has bothy copy ctor and assignment op as private, which explains the second error message. The first error message has something to do with the WindowHandle class, which you haven't shown.
To make much more sense of this, we'd need to see the Window class too - does it (for example) have a default constructor?
I suppose I'm going to get thoroughly trashed for that (read till the end before going all fuming) but... assuming the constructor of windows never throws:
void MyClass::init()
{
obj::~Window(); // destroy the object
new (&obj) Window(...); // construct the object
};
I shall of course underline the not throw requirement of the constructor as if it throws you'll be left with a very muddy situation: the destructor of MyClass will call the destructor of Window regardless of whether or not the object is alive and kicking or trashed because of a failed construction, and in the latter case you get undefined behavior.
Of course, a typical thing will thus be std::unique_ptr<Window> but we have the hurdle of dynamic allocation where clearly the situation does not mandate it...
So you'd be better off using a library: Boost.Optional.
class MyClass
{
public:
private:
boost::optional<Window> obj;
};
The syntax invocation is similar to a pointer:
obj->foo();
But the one benefit is that you get inplace destruction / construction with safer semantics. Destruction is easy:
// both call ~Window() if an instance had been constructed
obj.reset();
obj = detail::none_t();
For construction use a TypedInPlaceFactory. And for assignment too... which of course clears up the previous instance (if any) first:
void MyClass::init(Arg1 arg1, Arg2 arg2)
{
obj = boost::in_place<Window>(arg1, arg2);
}
The main advantage is that if any exception is now encountered during construction, the optional object is left in the unitialized state, which is perfectly viable, and thus you need not fear undefined behavior.
So basically it's like having a dynamically allocated object owned by a smart pointer... except that the magic is that the object is not dynamically allocated, thus guaranteeing the very same performances that a "normal" object :)
I should add that the non-copyable hurdle is one of the reason behind the InPlaceFactory creation.
The whole point is not letting you clone it.
Initialize like this: Window obj(parameters of other constructor, not the copy one)
or
Window &obj = somefunctionConstructingSuchAWindow();
If Window doesn't have a copy constructor, you cannot assign another object of class Window to it. You can initialize obj only from the constructor of MyClass using an initializer list. For example:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass()
: obj(/*constructor params*/)
{
/*...*/
}
}
The initialization of class members should be done on class constructor like on the following example:
class MyClass
{
public:
MyClass(/* constructor params */);
private:
Window m_obj; // Hasn't copy constructor
};
MyClass::MyClass(/* constructor params */) : m_obj(/* constructor params */)
{
}