Array objects initialization whose class has some ctor / dtor - c++

I would like to realize array objects initialization by using the initialization statement as follows.
TestClass array[5] = {
TestClass("test1"),
TestClass("test2"),
TestClass("test3"),
TestClass("test4"),
TestClass("test5")
};
According to some authoritative book like ARM (annotated reference manual) for C++, it seems that it says that this is the way to initialize object array which has constructor / destructor. Following this, I've just created the following sample code and see what happens.
#include <iostream>
#include <sstream>
#include <string>
class TestClass
{
public:
TestClass(const char* name) : name_(name)
{
std::cout << "Ctor(const char*) : " << name_ << std::endl;
}
~TestClass()
{
std::cout << "Dtor() : " << name_ << std::endl;
}
TestClass() : name_("")
{
}
void print()
{
std::cout << "obj:" << name_ << std::endl;
}
private:
TestClass(const TestClass& rhs);
std::string name_;
};
int main()
{
TestClass array[5] = {
TestClass("test1"),
TestClass("test2"),
TestClass("test3"),
TestClass("test4"),
TestClass("test5")
};
for (unsigned int i = 0; i < sizeof(array)/sizeof(array[0]); ++i) {
array[i].print();
}
return EXIT_SUCCESS;
}
As for the first trial to compile the above source code using GNU GCC (4.1.2), it failed by generating something like the following.
error: ‘TestClass::TestClass(const TestClass&)’ is private
So I understood that this means that in order to allow object array initialization, it would require 'copy constructor'. Then I tried to compile the above code by introducing user-defined (public) copy constructor as follows.
TestClass::TestClass(const TestClass& rhs) : name_(rhs.name_)
{
std::cout << "Copy Ctor : " << name_ << std::endl;
}
I could successfully compile the source code. However, when I execute the program which has been built the above, I got the following output.
Ctor(const char*) : test1
Ctor(const char*) : test2
Ctor(const char*) : test3
Ctor(const char*) : test4
Ctor(const char*) : test5
obj:test1
obj:test2
obj:test3
obj:test4
obj:test5
Dtor() : test5
Dtor() : test4
Dtor() : test3
Dtor() : test2
Dtor() : test1
What I'm curious to know is the following,
Why we cannot make the copy constructor declared as private?
Why the user-defined copy constructor is not invoked (I expected that the output should have included "Copy Ctor : xxxx" somewhere. But I couldn't get that. So I understood the user-defined copy constructor has not been invoked.)
Actually, I'm not really sure whether the above is specific to GNU GCC or this is C++ language specification... It would be appreciated if some of you could give me the correct pointer on the above.

The compiler elides the copy, but the copy-constructor still has to be accessible.

Whether of not the copy constructor is used by the compiler, it must be accessible - i.e. it must not be private. In this case, the compiler could avoid using the copy constructor, by using the const char * constructor directly, but it still needs an accessible copy ctor. This is the kind of thing not covered in the ARM, which is way out of date.

Related

overloaded functions skipped on references

The below code attempts to implement basic Decorator Design Pattern using references to refer to the base component class Paragraph
#include <string>
#include <iostream>
using std::cout; using std::endl; using std::string;
// component
class Paragraph{
public:
Paragraph(const string& text = "") : text_(text) {}
virtual string getHTML() const { return text_; }
private:
const string text_;
};
// first decorator
class BoldParagraph : public Paragraph {
public:
BoldParagraph(const Paragraph& wrapped): wrapped_(wrapped) {}
string getHTML() const override {
return "<b>" + wrapped_.getHTML() + "</b>";
}
private:
const Paragraph &wrapped_;
};
// second decorator
class ItalicParagraph : public Paragraph {
public:
ItalicParagraph(const Paragraph& wrapped): wrapped_(wrapped) {}
string getHTML() const override {
return "<i>" + wrapped_.getHTML() + "</i>";
}
private:
const Paragraph &wrapped_;
};
int main(){
Paragraph p("Hello, World!");
BoldParagraph bp(p); cout << bp.getHTML() << endl;
BoldParagraph bbp(bp); cout << bbp.getHTML() << endl;
ItalicParagraph ibp(bp); cout << ibp.getHTML() << endl;
}
When run, it produces
<b>Hello, World!</b>
<b>Hello, World!</b>
<i><b>Hello, World!</b></i>
rather than
<b>Hello, World!</b>
<b><b>Hello, World!</b></b>
<i><b>Hello, World!</b></i>
That is, the second wrapped function getHML() appears to be skipped if it is for the same subclass BoldParagraph for object bbp, but not if it is for different subclasses ItalicParagraph and BoldParagraph for object ibp. Similar code with pointers rather than references works as expected.
why is that?
The reason is that bbp(bp) with bp being of type BoldParagraph calls the (implicitly defined) copy constructor BoldParagraph::BoldParagraph(const BoldParagraph &)This then performs a member wise copy/assignment, such that wrapper_ gets sliced and will then be of type Paragraph & rather than BoldParagraph &. To overcome this, you'll have to provide an explicit copy constructor for BoldParagraph::BoldParagraph(const BoldParagraph &), which then calls your individual one:
BoldParagraph(const BoldParagraph& wrapped) : BoldParagraph((Paragraph&)wrapped) {} ;
The default copy constructor is being called. This creates a copy of your original object passed in (bp), rather than a wrapper around bp. You could fix by declaring your own copy constructor, but I don't recommend it:
BoldParagraph(const BoldParagraph &wrapped) : wrapped_(wrapped) {}
To clarify, the default copy constructor copies the values passed in object, like so:
BoldParagraph(const BoldParagraph &original) : wrapped_(original.wrapped_) {}
And, the more I think about it, the more I think my suggested fix is incorrect. There can/probably will be nasty side-effects. I would recommend fixing by making your constructors take pointers.
Answers here will show possible side-effects of having a copy constructor that does not perform a copy:
Copy Constructor in C++ is called when object is returned from a function?
A concrete example using a copy constructor that wraps instead of copies:
void AFunction(BoldParagraph bp)
{
cout << bp.getHTML() << endl;
}
int main() {
Paragraph p("Hello, World!");
BoldParagraph bp(p); cout << bp.getHTML() << endl;
BoldParagraph bbp(bp); cout << bbp.getHTML() << endl;
AFunction(bbp);
output:
<b>Hello, World!</b>
<b><b>Hello, World!</b></b>
<b><b><b>Hello, World!</b></b></b>
Oh, great, thank you much! That was hard to spot. I ended up adding this
BoldParagraph(const BoldParagraph& wrapped) :
BoldParagraph(static_cast<const Paragraph&>(wrapped)) {}
to make the code happy

std::move used, move constructor called but object still valid

Can someone explain why the original object that is passed to a new object via std::move is still valid afterwards?
#include <iostream>
class Class
{
public:
explicit Class(const double& tt) : m_type(tt)
{
std::cout << "defaultish" << std::endl;
};
explicit Class(const Class& val) :
m_type(val.m_type)
{
std::cout << "copy" << std::endl;
};
explicit Class(Class&& val) :
m_type(val.m_type)
{
m_type = val.m_type;
std::cout << "move: " << m_type << std::endl;
};
void print()
{
std::cout << "print: " << m_type << std::endl;
}
void set(const double& tt)
{
m_type = tt;
}
private:
double m_type;
};
int main ()
{
Class cc(3.2);
Class c2(std::move(cc));
c2.print();
cc.set(4.0);
cc.print();
return 0;
}
It outputs the following:
defaultish
move: 3.2
print: 3.2
print: 4
I would expect the calls to cc.set() and cc.print() to fail...
UPDATE
Thanks to answers below, we've identified that 1) I wasn't moving anything in the move constructor, and 2) std::move() on an int or double doesn't do anything because it's more expensive to move these types than to simply copy. The new code below updates the class's private member variable to be of type std::string instead of a double, and properly calls std::move when setting this private member variable in the Class' move constructor, resulting in an output that shows how a std::move results in a valid but unspecified state
#include <iostream>
#include <string>
class Class
{
public:
explicit Class(const std::string& tt) : m_type(tt)
{
std::cout << "defaultish" << std::endl;
};
explicit Class(const Class& val) :
m_type(val.m_type)
{
std::cout << "copy" << std::endl;
};
explicit Class(Class&& val) : m_type(std::move(val.m_type))
{
std::cout << "move: " << m_type << std::endl;
};
void print()
{
std::cout << "print: " << m_type << std::endl;
}
void set(const std::string val )
{
m_type = val;
}
private:
std::string m_type;
};
int main ()
{
Class cc("3.2");
Class c2(std::move(cc));
c2.print( );
cc.print();
cc.set( "4.0" );
cc.print();
return 0;
}
And finally the output:
defaultish
move: 3.2
print: 3.2
print:
print: 4.0
Because the standard says so.
Moved-from objects have a valid but unspecified state. That means you can still use them, but you can't be sure what state they'll be in. They could look just as they did before the move, depending on what is the most efficient way to "move" data out of them. For example, "moving" from an int makes no sense (you'd have to do extra work to reset the original value!) so a "move" from an int is actually only ever going to be a copy. The same is true of a double.
Although in this case it's got more to do with the fact that you didn't actually move anything.
In the code example, std::move determines which constructor gets called. Nothing more. So c2(std::move(cc)) calls the move constructor for Class. The move constructor for Class doesn't do anything to its argument, so cc is unchanged, and it can be used just as it could have before the call to the move constructor.
All the talk in comments and answers about the state of an object that has been moved from is about the requirements on standard library types, which will be left in a "valid but unspecified state" (17.6.5.15, [lib.types.movedfrom]). What you do with your types is not affected by that.
EDIT: sigh. You edited the code and changed the question. Now that your class holds a std::string instead of a float things are different, and the std::string object in cc is, indeed, in a "valid but unspecified state".

How do I prevent code repeat between rvalue and lvalue member functions?

For the program code below, I have to write the the same code inside the pair of member functions which receiving rvalue and lvalue references.
My aim is to use only one from the pair (e.g.; only use the rvalue accepting ones), and the others. I read the reference of std::forward, as far as I understood, it looks like it is for this purpose. But, when I delete the lvalue reference taking ones, I get the following compiler error.
'TestClass::TestClass(const TestClass &)': cannot convert argument 1 from 'std::wstring' to 'std::wstring &&'
How do I prevent this code duplication?
#include <iostream>
#include <string>
class TestClass
{
public:
TestClass(const std::wstring & Text)
: Text(Text)
{
std::wcout << L"LValue Constructor : " << Text << std::endl;
/*Some code here...*/
}
TestClass( std::wstring && Text)
: Text(std::forward<std::wstring>(Text))
{
std::wcout << L"RValue Constructor : " << this->Text << std::endl;
/*Same code here...*/
}
TestClass(const TestClass & Another)
: Text(Another.Text)
{
std::wcout << L"Copy Constructor : " << Text << std::endl;
/*Some code here...*/
}
TestClass( TestClass && Another)
: Text(std::forward<std::wstring>(Another.Text))
{
std::wcout << L"Move Constructor : " << Text << std::endl;
/*Same code here...*/
}
private:
std::wstring Text;
};
int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
std::wstring Argument(L"Testing Copy");
TestClass Class1Copy(Argument);
TestClass Class1Move(L"Testing Move");
TestClass Class2Copy(Class1Copy);
TestClass Class2Move(std::move(Class1Move));
_wsystem(L"pause");
return 0;
}
Output:
LValue Constructor : Testing Copy
RValue Constructor : Testing Move
Copy Constructor : Testing Copy
Move Constructor : Testing Move
Press any key to continue . . .
If move construction is expected to be extremely cheap, you can take by value and move-from the value. This does exactly 1 more move than a pair of copy and move overloads.
If you want optimal efficiency, and/or if move construction is cheaper but not cheap enough to neglect, you can forward:
template<class T>
std::decay_t<T> copy(T&& t) {
return std::forward<T>(t);
}
class TestClass {
public:
TestClass(std::wstring const& Text)
TestClass( copy(Text) )
{}
TestClass(TestClass const& o)
: TestClass( o.Text )
{}
TestClass(TestClass&& o)
: TestClass( std::move(o).Text ) // pattern does the right thing more often than `std::move(o.Text)` does.
{}
// only "real" ctor:
TestClass( std::wstring&& Text)
: Text(std::forward<std::wstring>(Text))
{
std::wcout << L"RValue Constructor : " << this->Text << std::endl;
/*Code here...*/
}
// ...
now everything forwards down to the one constructor.
You can even mix the two techniques: use by-value for std::wstring (as we know that is cheap-to-move) and do forwarding stuff for the TestClass code (or anything less likely to be stable).
You can take by value and then move. Then you only need N overloads, not 2N:
TestClass(std::wstring Text)
: Text(std::move(Text))
{
}
You can avoid the copy constructor and move constructor duplication by writing nothing at all; the compiler will generate them by default in this case.
I don't think you can do that since the function's signatures determine when and where they are used. It's like a copy constructor and an assignment operator. They do somewhat similar things but the compiler calls the appropriate one basee on context.
If you want to avoid reusing code, just factor out the commonality into a separate function.

C++ const std::string assignment

What is most appropriate in const std::string assignment/declaration? Using the constructor(e.g., const std::string WORD("hello");) or using equal operator(e.g., const std::string WORD= "hello";)?
Does these things has difference in memory usage or time processes?
For any reasonable compiler, the code generated will be the same in both cases. Whether you should use direct initialization or copy-initialization in this case is essentially opinion-based.
In both cases, generally compilers will remove the copies using "Return Value Optimisation" anyway. See this code on ideone here calls neither the ordinary constructor nor the assignment operator as it doesn't print that they're being called to screen:
That is:
#include <iostream>
class C
{
public:
C() {}
C(const char[]) { std::cout << "Ordinary Constructor" << std::endl; }
C& operator=(const char[]) { std::cout << "Assignment Operator" << std::endl; return *this; }
};
int main() {
std::cout << "Start" << std::endl;
C x1 = "Hello";
C x2("Hello");
std::cout << "End" << std::endl;
}
Simply outputs:
Start
End
It doesn't output:
Start
Assignment Operator
Ordinary Constructor
End
As C++ allows the copies to be skipped and the temporary to be constructed in place.
The lines:
std::string x = "hello";
std::string x("hello");
both will only call the constructor of std::string. That is, they are identical, and neither will use the operator= overloads.

Why is copy-constructor not called in this case?

I encountered a code snippet and thought that it would call copy-constructor but in contrast , it simply called normal constructor . Below is the code
#include <iostream>
using namespace std;
class B
{
public:
B(const char* str = "\0")
{
cout << "Constructor called" << endl;
}
B(const B &b)
{
cout << "Copy constructor called" << endl;
}
};
int main()
{
B ob = "copy me";
return 0;
}
What you've discovered that B ob = "copy me"; notionally creates a B from the literal and then copy constructs ob, but that the compiler is allowed to elide the copy and construct directory into ob. g++ even elides the copy with no optimization enabled at all.
You can observe that this is the case by making your copy constructor private: The code will fail to compile even though the compiler won't actually use the copy constructor (the standard requires that copy constructors be accessible even when the call is elided).