One question about array without default constructor in C++ - c++

From previous post, I learnt that for there are two ways, at least, to declare an array without default constructors. Like this
class Foo{
public:
Foo(int i) {}
};
Foo f[5] = {1,2,3,4,5};
Foo f[5] = {Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)};
I also learnt that the first one will construct the object using the parameter directly and the second copy constructor is used here. However, when I test the code below. I make the copy constructor private. I expect to see the difference of the copy constructor usage. But it is not what I expected. Neither of the two declarations is working.
class Foo{
public:
Foo(int i) {}
private:
Foo(const Foo& f) {}
};
int main(){
Foo f[5] = {1,2,3,4,5};
Foo f[5] = {Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)};
}
Can anybody explain to me why does this happen?

The first won't construct the objects directly. It will first construct a temporary Foo, and then copy the Foo into the element. It's similar to your second way. The difference is that your second way won't work with a explicit copy constructor, while your first will. And conversely, the first will not work with a explicit constructor taking int, while the second will. Stated another way, the first constructor used in the initialization of an element must not be explicit.
Notice that neither way needs to copy. But they still need to check whether the copy constructors are accessible. So, they shall behave as-if they would copy, but they don't really need to do the copy.

Related

Is there a way in C++ to deep copy only required variables in CCTOR? [duplicate]

I have a long class with a lot of data members. I want to write a copy constructor for it. But, if I write my own copy constructor, I lose access to the default copy constructor.
I just want to repair a few pointers in my own copy constructor. So I want to have a shallow copy of the object which can be done by the default copy constructor.
Is there a possibility to access the default copy constructor when I have my own copy constructor?
Wrap the things you don't want to change in a struct, and derive (privately) from it. In your copy constructor, simply invoke the copy constructor of your base class.
No you cannot have both default and your own copy c-tor.
But there are two workarounds with this problem:
1 Enclose your pointers in some class with defined copy semantics
Example:
class A {
public:
private:
int trivial1;
int trivial2;
...
SomePointer nontrivialMember;
};
class SomePointer {
public:
SomePointer(const SomePointer&); // here the non trivial part of A copy semantics
int* nonTrivialMember;
};
2 Enclose the trivial parameters in some trivial structure
Example:
class A {
public:
A(const A& o) : data(o.data) {
// non trivial part
}
private:
struct Data {
int trivial1;
int trivial2;
...
} data;
int* nontrivialMember;
};
I would always select the first solution.
[UPDATE]
There is also 3rd solution, very similar to my second, enclose your trivial part in privately inherited base class. I'd still prefer the 1st solution.
The simplest approach to this would be to wrap up the pointers into classes that will perform the 'repair' manually in their copy constructor, then you can happily use the default copy constructor.
No, there is no way to call the default copy constructor from an user defined copy constructor.
You can either use the default or your own, not both. If you want to choose different functionality for different objects you should just write a member function that handles that case.
void DeepCopy(MyClass* rhs);
For example.
You cannot access default copy ctor if you created your own - compiler just doesn't generate it. But ther is workaround - split you class into data structure and logic.
See example:
struct Data
{
int i;
std::string s;
Data(): i(), s() {}
};
class Code: private Data
{
public:
Code() {}
Code(const Code& rhs): Data(rhs) // Call default copy ctor
{
i = 42; // Your copy part
return *this;
}
};
My solution is a simple memcpy() instead of the impossible call to the implicit (compiler generated) copy constructor, as the example shown below:
Class Foo
{
public:
...
Foo (Foo & other) {
// copies trivial part (and non-trivial part with possible wrong values)
memcpy(this, &other, sizeof(Foo));
// your non-trivial part here, overwrites the wrong values (if any) above.
}
}
Yet the side-effect is that the memcpy() will also copy those non-trivial part, which is a waste. If the non-trivial part does not contain too much space, I will prefer my solution.
For example, a class like below wastes only 4 byte copy of the one pointer, assuming the size of a pointer is 4 bytes.
Class Bar
{
int x, y, z;
// memcpy() wastes these 4 bytes copy,
// since actual copy constructor wants a new string
string *s;
}
This worked for me... (C++11, don't know if it works on older std)
Not sure why it doesn't end up in an endless loop.
class Foo {
public:
Foo(const Foo &orig) {
*this = orig;
... exchange pointers, do own stuff
}

C++ member initializer list for member array of non-copyable objects

I have an object which is non-copyable and which requires an argument to its contructor:
class Foo
{
public:
Foo() = delete;
Foo(const Foo &) = delete;
Foo(int x);
private:
int member;
};
Foo::Foo(int x) : member(x)
{
}
I have another class which contains as a member an array of such objects:
class Bar
{
public:
Bar(int a);
private:
Foo members[4];
};
Suppose that my object Foo is really far too big and its constructor far too complicated for a temporary or duplicate copy to ever exist or the constructor to ever be called more than once for each item of the array.
How do I write the constructor for the containing class to pass the arguments to the items in the member array?
I have tried:
Bar::Bar(int a) : members { a, a+1, a+2, a+3 }
{
}
g++ says "use of deleted function Foo::Foo(const Foo&)".
[Edit] I have also tried:
Bar::Bar(int a) : members { {a}, {a+1}, {a+2}, {a+3} }
{
}
as suggested by Yksisarvinen. This also says "use of deleted function Foo::Foo(const Foo&)", but only if I declare a destructor for Foo. Without a destructor this compiles correctly. How do I get it to compile for a class which has a destructor?
Three options here, depending on what you actually want to do:
1. Use C++17
C++17 has guaranteed copy elision, which will solve the problem.
2. Provide a move constructor
Compiler chooses copy constructor, because by declaring your own copy constructor you prevented possibility to generate a move constructor. Depending on your actual class, move constructor may or may not be viable.
Foo(Foo &&) = default; //or implement "stealing" of the resource here
Note that by the rule of five you should also provide copy/move assignment operators and destructor (defaulted or not).
3. Wrap each array element in braces
If neither of above options is valid, the workaround is to simply wrap each of the array elements in its own set of braces
Bar::Bar(int a) : members { {a}, {a+1}, {a+2}, {a+3} }
In general, your previous option relied on conversion from int to Foo. Once the compiler does the conversion, it has to copy (or move, but you excluded that) the converted object to array, and that triggers an error. By wrapping them in braces, the elements are initialized as Foo objects (and not as int to be converted to Foo), and no move/copy is needed.

Copy constructor implicit conversion problem

Part of the answer is given in here
class foo1
{
private:
int i;
public:
foo1()
{
i=2;
}
int geti(){
return i;
}
};
class foo2
{
private:
int j;
public:
explicit foo2(foo1& obj1) //This ctor doesn't have `const` intentionally as i wanted to understand the behavior.
{
cout<<"\nctor of foo2 invoked";
j=obj1.geti();
}
};
foo1 obj1;
foo2 obj2(obj1); //THIS WORKS
foo2 obj22=obj1; //THIS DOESN'T WORK
Both of them work when the keywork explicit is removed.
Is the following explanation correct for copy initialization( foo2 obj22=obj1) :
At first the compiler creates a temporary object using constructor:
foo2(foo1& other) {}
then it tries to use this temporary object in the copy constructor:
foo2(foo2& other) {}
But it may not bind a temporary object with non-constant reference and it issues an error.
When you are using the equal sign then there is used so-called copy-initialization.
If yes, then shouldn't foo2(foo1& other) {} itself be disallowed before even going further because temporary cannot be bound to non const reference?
Sorry for the long question, my confusion is basically around difference behavior for direct and copy initialization in presence/absence of explicit keyword(with/without const)
Is the following explanation correct for copy initialization
It isn't. You omitted the definition of a copy c'tor for foo2. Which means the compiler synthesizes one for you automatically. The synthesized version will take by a const foo2&. So the issue is not in binding a temporary foo2 to a non-const reference.
As a matter of fact, copy initialization no longer creates temporaries, and doesn't even have to behave as though a temporary is present. What instead happens is that the form of initialization simply takes the explicit keyword into account.
Both of these
foo2 obj2(obj1);
foo2 obj22=obj1;
perform the same overload resolution, which can only choose the same c'tor (foo2(foo1& obj1)). It should choose this c'tor because you pass a non-const lvalue for an argument.
The difference? Direct initialization is allowed to use an explicit c'tor. While copy initialization does not. So your explicit c'tor is not a candidate, and overload resolution fails.

trivial assignment

In trying to understand this answer, it seems that new can be classified as a "copy constructor" and delete sometimes as a "trivial destructor".
I can find next to nothing (that I can quickly grasp) on "trivial assignment" except that it is "trivial if it is implicitly declared, if its class has no virtual member functions or virtual base classes, and if its direct base classes and embedded objects have a trivial assignment operator".
I found a question on yahoo about implicit declaration, but to my surprise, it did not answer.
My brain hurts after reading about virtual member functions.
Besides, I'm a monkey-see-monkey-do programmer, so the only way I'm going to get this is to see it in action. Please explain with respect to the above definition of "trivial" by using the example provided in the first answer, that std::string has a trivial assignment operator by using new or delete or for a less apparent reason.
New can use a copy constructor, and delete uses a destructor. The copy constructor or destructor may be trivial.
That being said, there is a STRONG chance that you will not need to worry about whether a constructor/destructor is trivial for a long time.
new calls a constructor to construct the object. If the one argument to the constructor of type T is an instance of T that is a copy constructor: you are trying to construct an instance of one object from another
class Foo
{
public:
Foo(int x) // not a copy constructor
: mX(x)
{ }
Foo(const Foo& inOther) // copy constructor
: mX(inOther.mX)
{ }
private:
int mX;
};
class Bar
{
public:
Bar(int x)
: mX(x)
{ }
// no copy constructor specified.. C++ will build an implicit one for you
private:
int mX;
}
};
Foo a(1); // uses the first constructor (not a copy)
Foo b(a); // uses a copy constructor
Foo c = a; // copy constructor
Foo* d = new Foo(1); // construct a new instance of Foo (not a copy)
Foo* e = new Foo(a); // copy
Bar f(1); // normal constructor
Bar g(f); // IMPLICIT copy constructor
If your class does not have a copy constructor, like Bar, C++ usually provides you one (always provides you one unless you have an explicit constructor or delete the copy constructor with a C++11 keyword). This copy constructor is very straightforward: it copies each member of your class.
A trivial copy constructor is special. A trivial copy constructor can only be created when the copy constructor is implicitly created for you by the compiler and:
All members of your class are trivially copyable
You do not have any virtual methods or virtual base classes
All of your base classes are trivially copyable.
If you specify a constructor in your class, it is not trivial, by definition. Foo does not have a trivial copy constructor because it is user defined. Bar has an implicit copy constructor because it is not user defined. The implicit copy constructor IS trivial, because copying mX is trivial (copying ints is trivial).
Similar rules go for destructors. A trivial destructor follows the same rules, and delete
WHat does it do for you? The spec lists a few key behaviors about trivial constructors/destructors. In particular, there's a list of things you can do if you have a trivial constructor and destructor that are illegal otherwise. However, they are all very nuanced, and unimportant to 99.9% of C++ code development. They all deal with situations where you can get away with not constructing or destructing an object.
For example, if I have a union:
union MyUnion {
int x;
ClassA y;
ClassB z;
}
If y and z have trivial constructors and destructors, C+ will write a copy constructor for that union for me. If one of them has a non-trivial constructor/destructor, I have to write the copy constructor for the union myself.
Another thing you can do is fast destruction of an array. Usually, when you delete an array, you have to make sure to call the destructor on every item. If you can prove that the destructor of each element is trivial, then you are allowed to skip destroying the elements, and just free the memory. std::vector does this under the hood (so you don't have to)

Passing temporary object as parameter by value - is copy constructor called?

If a have a class with both standard and copy constructors
class Ex{
//constructor definitions
}
and a function that takes it as an argument (by value)
void F(Ex _exin){...}
take the following piece of code:
Ex A;
F(A); //F's parameter is copy constructed from A
F(Ex()); //F's parameter uses the default constructor
In the third line I'm passing to F a new (temporary) object of the Ex class using the default constructor. My question is: after this new object is created is it also copy constructed/assigned (like it happens in the second line) or is it directly created "inside" F?
It was hard to find, but honestly it was bugging me. This is called copy constructor elision.
The standard illustrates this example:
class X{
public:
X(int);
X(const X&);
~X()
};
X f(X);
void g()
{
X a(1);
X b = f(X(2)); //identical to what you have:
a = f(a);
}
And it states:
12.2/2 Temporary objects
Here, an implementation might use a temporary in which to construct
X(2) before passing it to f() using X's copy-constructor;
alternatively, X(2) might be constructed in the space used to hold the
argument. /.../
After this the standard explains return value optimization, which is basically the same thing.
So it actually has nothing to do with observed behavior, it is up to the compiler.
it should call the constructor and the copy-constructor
optimizers could delete unnecessary copying