Copy constructor converts from const to non-const? - c++

Consider the following :
class A
{
public:
int xx;
A(const A& other)
{
cout << "A cctor" << endl;
/* do some stuff */
}
A(int x) : xx(x) {} /* conversion constructor */
};
int main()
{
A a = 1;
A other = a;
return 0;
}
Is it right to say that CCtor converts from const to non-const in this case (and also in general) ?
Thanks ,Ron

A copy constructor creates a new copy of an existing object, that object may or may not be const. The const in A::A(const A& other) just says we are not going to change other in the copy ctor. Indeed if you attempt to modify other inside the ctor the compiler will moan at you.
The created object also may or may not be const depending on how you declare it.

No idea what you mean. A(const A&) is a typical copy-ctor, which has a "read-only" access to its only argument. If you pass anything const, everything is fine. If you pass anything non-const, for ctor it becomes const. A a = 1 is a conversion ctor, as you said. A other = a is a copy ctor. What's the question?
Regarding your question's title, in C++ there's no fair way to convert const to non-const.
class A
{
public:
int xx;
A(const A& other)
{
cout << "A cctor" << endl;
/* do some stuff */
// other is const here - you can only call its
// const methods and read all its data members
}
A(int x) : xx(x) {} /* conversion constructor */
// at this point, x is not const, but it's a copy
// of an object you've passed here, not the object itself
// you can change x, it just doesn't matter - you
// change the copy
};
int main()
{
A a = 1; // a is not const, 1 is passed "by value", since it's primitive type
A other = a; // a is not const, other is not const, a is passed by const reference
return 0;
}

Constructor initializes a new copy. And there is no problem in copying from a constant.
No conversion is involved.

What do you mean by CCtor converts from const to non-const?
If you mean, the non-const object gets created from the const object by invoking the copy-constructor, then yes. But that doesn't mean the const-object itself becomes non-const inside the copy-constructor (or at the call site). It only means that the newly constructed object is created by copying the existing object which is passed as const reference to the copy-constructor.

No the copy constructor creates an copy of the class object by taking another class object as the parameter.
Since in order to construct the new object being passed as parameter is not required to be modified it it passed as an const.

No, it's not converting to a non-const object. Consider this:
A a(42);
const A another = a;
Here, another is a const object, created from a non-const object.
More important, however, is that a constructor creates a new object from an existing one. Whether that new object is const or not does not depend on the existing object. All four possible combinations of const/non-const old/new objects are possible.

In the sense that the A(int) constructor converts from int to A, yes it's true that your copy ctor A(const A&) "converts" from const A to A. For that matter it also "converts" from non-const A to A, since the const reference parameter can bind to either.
And since the same constructor is used to create a const object as to create a non-const one, that copy ctor can also "convert" from A or const A to const A.
I've used "convert" in quotes just because converting from a type to itself or a cv-qualified version of itself is perhaps a confusing use of the term, normally you just call that "copying" rather than conversion.
The constructor parameter can bind to an instance of a derived class of A too, so you might say that it converts derived classes to A. That's normally called "slicing".
Strictly speaking it's not the copy ctor itself that converts anything, but a conversion to A (whether a cast or an implicit conversion) does depend on using a matching constructor. So I suppose the constructor can claim a large part of the credit.

Related

Error spotted in C++ Primer 5th Edition (copy intialization vs direct initialization)

Hi i am trying to understand how copy constructor works and looking at an example. The example is as follows:
{//new scope
Sales_data *p = new Sales_data;
auto p2 = make_shared<Saled_data>();
Sales_data item(*p); // copy constructor copies *p into item
vector<Sales_data> vec;
vec.push_back(*p2);// copies the object to which p2 points
delete p;
}
My question is :
Why it is written that "copy constructor copies *p into item"? I mean, item is direct initialized. If we would have written Sales_data item = *p; then it will be called copy initialized, so why they have written copy constructor copies *p into item in the comment.
Now, to verify this for myself, i tried creating a simple example myself, but there also i am unable to understand the concept properly. My custom example is as follows:
#include<iostream>
#include<string>
class MAINCLASS{
private:
std::string name;
int age =0;
public:
MAINCLASS(){
std::cout<<"This is default initialization"<<std::endl;
}
MAINCLASS(MAINCLASS &obj){
std::cout<<"This is direct initialization"<<std::endl;
}
MAINCLASS(const MAINCLASS &obj):name(obj.name),age(obj.age){
std::cout<<"This is copy initialization"<<std::endl;
}
};
int main(){
MAINCLASS objectone;
MAINCLASS objecttwo =objectone;
MAINCLASS objectthree(objectone);
return 0;
}
Now when i run this program, i get the following output:
This is defalut initialization
This is direct initialization
This is direct initialization
My question from this program is as follws:
Why are we not getting the output "this is copy initialization" in the second case when i write MAINCLASS objecttwo =objectone;? I have read that in direct initialization function matching is used and in copy constructor , we copy the right hand operand members into left hand operand members. So when i write MAINCLASS objecttwo =objectone; it should call the copy constructor and print "this is copy initialization" on the screen. But instead it is direct initializing the object. What is happening here?
Despite the poor choice of name, copy initialization is orthogonal to copy constructors.
A copy constructor is any constructor whose first parameter is a lvalue reference to its class type, and can be called with just one argument. It's just a constructor that can initialize new objects from existing objects. That's pretty much all there is to it. Both the constructors you declared are in fact copy constructors. This one would be too
MAINCLASS(MAINCLASS volatile &obj, void *cookie = nullptr) {
// .. Do something
// This is a copy c'tor since this is valid:
// MAINCLASS volatile vo;
// MAINCLASS copy1_vo(vo);
}
And as the other answers noted copy initialization is simply the name for a family of initialization contexts. It includes initialization involving =, passing arguments to functions, return statements and throw expressions (and I'm probably forgetting something). Direct initialization involves other contexts.
A copy constructor can be used in any of the above. Be it copy initialization or direct initialization. The difference between the two - as appertains to constructors - is how an overload set of constructors is built. Copy initialization doesn't make use of constructors declared explicit. For instance, in this example
struct Example {
Example() = default;
explicit Example(Example const&) {}
};
int main() {
Example e;
Example e1(e); // Okay, direct initialization
Example e2 = e1; // Error! Copy initialization doesn't make use of explicit constructor
}
Even though we have a copy constructor, it can't be called in a copy-initialization context!
As far as the unexpected print out of your program, it's simply a matter of overload resolution choosing a more matching function. Your origin object is not declared const. So binding it to a non-const lvalue reference is simply the preferred choice in overload resolution.
Don't confuse copy construction and copy initialisation. You can copy-construct using direct or copy initialisation.
Copy initialisation refers to a set of initialisation syntax and semantics. This includes the T a = b syntax.
The copy constructor is a special class method that takes an argument of said class. This method should only take one parameter (both T& or const T& will do). Copy construction occurs when that function is called.
With this in mind, we can go on to answer your questions.
Why it is written that "copy constructor copies *p into item"? I mean, item is direct initialized. If we would have written Sales_data item = *p; then it will be called copy initialized...
Both Sales_data item = *p and Sales_data item(*p) call the copy constructor. But, the former uses copy initialisation (T a = b), whereas the latter uses direct initialisation (T a(b)).
Why are we not getting the output "this is copy initialization" in the second case when i write MAINCLASS objecttwo =objectone;?
Actually, the issue here isn't whether it's copy/direct initialised. This is an issue of lvalue/rvalue overload resolution.
Consider the following program:
#include <iostream>
void f(int& i) { std::cout << "int&\n"; }
void f(const int& i) { std::cout << "const int&\n"; }
int main() {
f(1); // f(const int&)
int i = 2;
f(i); // f(int&)
}
f is chosen based on whether the value passed is lvalue or rvalue. In the first case, 1 is an rvalue, so f(const int&) is called (see this). In the second case, i is an lvalue, and f(int&) is chosen since it's more general.
So in your case, both MAINCLASS objecttwo =objectone; and MAINCLASS objectthree(objectone); call the copy constructor. And again, the former uses copy initialisation, whereas the latter uses direct initialisation. It's just that both of these calls choose the non-const ref overload instead: MAINCLASS(MAINCLASS&).
Copy initialization and direct initialization is based on the syntax used to construct.
See Confusion in copy initialization and direct initialization.
Which constructor gets invoked is based on overload resolution (and not the syntax to construct)
The compiler invokes the function which best matches the passed arguments to the defined parameters.
In your example since objectone is non-const, the best match is the copy constructor with a non-const parameter. Since the other copy constructor has a const& parameter, it will get invoked for a const object.
Rewriting your example:
#include<iostream>
#include<string>
class MAINCLASS {
private:
std::string name;
int age = 0;
public:
MAINCLASS() {
std::cout << "This is default initialization" << std::endl;
}
MAINCLASS(MAINCLASS& obj) {
std::cout << "This is copy constructor with non-const reference parameter" << std::endl;
}
MAINCLASS(const MAINCLASS& obj) :name(obj.name), age(obj.age) {
std::cout << "This is copy constructor with const reference parameter" << std::endl;
}
};
int main() {
MAINCLASS objectone;
const MAINCLASS const_objectone;
MAINCLASS objecttwo = objectone; // copy initialization of non-const object
MAINCLASS objectthree(objectone); // direct initialization of non-const object
MAINCLASS objectfour = const_objectone; // copy initialization of const object
MAINCLASS objectfive(const_objectone); // direct initialization of const object
return 0;
}
The output would be:
This is default initialization
This is default initialization
This is copy constructor with non-const reference parameter
This is copy constructor with non-const reference parameter
This is copy constructor with const reference parameter
This is copy constructor with const reference parameter

Why do I need const copy constructor when compiling my code with converting constructor?

I have such class in A.h :
class A {
public:
A(int *object) {
std::cout << "convert";
}
A(A &object) {
std::cout << "copy";
}
};
and in main.cpp
A a = new int;
then, when I'm trying to compile it i get
invalid initialization of non-const reference of type ‘A&’ from an
rvalue of type ‘A’
but when i add const to copy-constructor like that:
A(const A &object) {
std::cout << "copy";
}
code compiles and "convert" is called. It works when i remove copy constructor, too. Why such thing happen? I though this example has nothing to do with copying constructor as we do not use instance of class A to create another.
Because the way your code works is following (pre-C++17):
A a(A(new int));
Note, copy constructor of A is called with a temporary object crated as a result of A(new int). And you can't bind a non-const lvalue reference to a temporary.
Just a note, in C++17 this code will compile due to guaranteed copy-elision (in case of C++17, this code is semantically equivalent to A a(new int). You also won't see copy printed (because it will never be called due to copy elision)
A a = new int; is copy initialization. It takes what is on the right hand side and uses it to initialize what is on the left hand side as a copy of it. since new int isn't an A the compiler makes a temporary one calling the converting constructor. A temporary can't be bound to a non const reference so you get an error. When you add the const you can now bind the temporary to it and it will work. Removing the copy constructor also works as the compiler will provide one for you and the one it does takes in a const reference,

c++ Using const in a copy constructor?

I have never written copy constructor, so in order to avoid pain i wanted to know if what i have coded is legit. It compiles but i am not sure that it works as a copy constructor should.
Also do i have to use const in the copy constructor or i can simply drop it. (What i dont like about const is that the compiler cries if i use some non const functions).
//EditNode.h
class EditNode
{
explicit EditNode(QString elementName);
EditNode(const EditNode &src);
}
//EditNodeContainer.h
class EditNodeContainer : public EditNode
{
explicit EditNodeContainer(QString elementName);
EditNodeContainer(const EditNodeContainer &src);
}
//EditNodeContainer.cpp
EditNodeContainer::EditNodeContainer(QString elementName):EditNode(elementName)
{
}
//This seems to compile but not sure if it works
EditNodeContainer::EditNodeContainer(const EditNodeContainer &src):EditNode(src)
{
}
//the idea whould be to do something like this
EditNodeContainer *container1 = new EditNodeContainer("c1");
EditNodeContainer *copyContainer = new EditNodeContainer(container1);
A copy constructor is a constructor that has one of the following signatures:
class A
{
A(A& other);
//or
A(const A& other);
//or
A(volatile A& other);
//or
A(const volatile A& other);
//or any of the above + other parameters that have default arguments
//example:
A(const A& other, int x = 0) //this is also a copy constructor
};
The above is specified in 12.8.2 of the standard - C++03.
so you are implementing correctly a copy constructor.
The reason it should receive a const parameter is that you're not changing the object you're copying from. If you call non-const functions on it, you're doing something wrong.
Also, in your snippet
EditNodeContainer *container1 = new EditNodeContainer("c1");
EditNodeContainer *copyContainer = new EditNodeContainer(container1);
you're not calling a copy constructor, because you're passing an EditNodeContainer* as parameter, not a EditNodeContainer.
You're missing one * symbol. Copy constructor expects reference to object, but is given pointer to object. Just replace container1 with *container1 as parameter of copy constructor.
The parameter of a copy constructor can be an lvalue reference to non-const or an lvalue reference to const, but in practice it is always a reference to const (the deprecated auto_ptr is an exception).
You should not write a copy constructor unless you have to and you fully understand the consequences. If you are consequent in using RAII classes everywhere, you rarely need a custom copy constructor (unless you are writing a RAII class).
Also, please avoid raw pointers and new wherever possible.

Can we return objects having a deleted/private copy/move constructor by value from a function?

In C++03 it is impossible to return an object of a class having a private non-defined copy constructor by value:
struct A { A(int x) { ... } private: A(A const&); };
A f() {
return A(10); // error!
return 10; // error too!
}
I was wondering, was this restriction lifted in C++11, making it possible to write functions having a class type return type for classes without constructors used for copy or move? I remember it could be useful to allow callers of a function use the newly returned object, but that they are not able to copy the value and store it somewhere.
Here is how it can work
A f() {
return { 10 };
}
This works even though A has no working copy or move constructor and no other constructor that could copy or move an A!
To make use of this feature of C++11, the constructor (taking int in this case) has to be non-explicit though.
The restriction has not been lifted. As per the access specifier, there is a note in §12.8/32 that explains:
two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided.
As of the deleted copy/move constructors §8.4.3/2 states that
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. — end note ]
Not sure about this particular case, but my understanding of the quote is that, if after the overload resolution in §12.8/32 the deleted copy/move constructor is selected, even if the operation is elided, that could constitute a reference to the function, and the program would be ill formed.
The above code is still ill-formed in C++11. But you could add a public move constructor to A and then it would be legal:
struct A
{
A(int x) {}
A(A&&);
private:
A(A const&);
};
A f() {
return A(10); // Ok!
}
I was wondering, was this restriction lifted in C++11?
How could it be? By returning something by value, you are by definition copying (or moving) it. And while C++ can allow that copy/move to be elided in certain circumstances, it's still copying (or moving) by the specification.
I remember it could be useful to allow callers of a function use the returned object, but that they are not able to copy the value and store it somewhere.
Yes. You get rid of the copy constructor/assignment, but allow the value to be moved. std::unique_ptr does this.
You can return a unique_ptr by value. But in doing so, you are returning an "prvalue": a temporary that is being destroyed. Therefore, if you have a function g as such:
std::unique_ptr<SomeType> g() {...}
You can do this:
std::unique_ptr<SomeType> value = g();
But not this:
std::unique_ptr<SomeType> value1 = g();
std::unique_ptr<SomeType> value2 = g();
value1 = value 2;
But this is possible:
std::unique_ptr<SomeType> value = g();
value = g();
The second line invokes the move assignment operator on value. It will delete the old pointer and move the new pointer into it, leaving the old value empty.
In this way, you can ensure that the contents of any unique_ptr is only ever stored in one place. You can't stop them from referencing it in multiple places (via pointers to unique_ptr or whatever), but there will be at most one location in memory where the actual pointer is stored.
Removing both the copy and move constructors creates an immobile object. Where it is created is where it's values stay, forever. Movement allows you to have unique ownership, but without being immobile.
You could probably hack together a proxy to do the trick if you really wanted, and have a converting constructor that copies the value stored within the proxy.
Something along the lines of:
template<typename T>
struct ReturnProxy {
//This could be made private, provided appropriate frienship is granted
ReturnProxy(T* p_) : p(p_) { }
ReturnProxy(ReturnProxy&&) = default;
private:
//don't want these Proxies sticking around...
ReturnProxy(const ReturnProxy&) = delete;
void operator =(const ReturnProxy&) = delete;
void operator =(ReturnProxy&&) = delete;
struct SUPER_FRIENDS { typedef T GO; };
friend struct SUPER_FRIENDS::GO;
unique_ptr<T> p;
};
struct Object {
Object() : data(0) { }
//Pseudo-copy constructor
Object(ReturnProxy<Object>&& proxy)
: data(proxy.p ? proxy.p->data : throw "Don't get sneaky with me \\glare")
{
//steals `proxy.p` so that there isn't a second copy of this object floating around
//shouldn't be necessary, but some men just want to watch the world burn.
unique_ptr<Object> thief(std::move(proxy.p));
}
private:
int data;
Object(const Object&) = delete;
void operator =(const Object&) = delete;
};
ReturnProxy<Object> func() {
return ReturnProxy(new Object);
}
int main() {
Object o(func());
}
You could probably do the same in 03, though, using auto_ptrs. And it obviously doesn't prevent storage of the resultant Object, although it does limit you to one copy per instance.

why do we have to send the const " type " reference instead of just the types name to the constructor

i m trying to make a simple program ( & yes , it is a homework ) that can generate Dates , & like most of normal people : i made my Class attributes private , i tried to send the same type that i m working on to the constructor but the complier have not accept it , i did some research & i found out that in cases like that people generously send a const "type" reference to the constructor witch meant to me that have not understand OOP well
so why do we have to send the const " type " reference instead of just the types name to the constructor ? & please give me some links or websites for beginners
here is a peace of my Code :
class Date {
int d ;
int m ;
int y ;
public :
Date();
Date(int , int , int);
Date(const Date &);// my question is : why do we have to write this instead of Date( Date )
};
PS : sorry for my English
To paraphrase our question:
why do we have to write Date(const Date &) instead of Date(Date)?
I'm going to split this into two parts, the first answering why a copy constructor needs to take its argument per reference, the second why this needs to be a const reference.
The reason a copy constructor needs to take its argument per reference is that, for a function that's taking an argument per copy void f(T arg), when you call it f(obj), obj is copied into arg using T's copy constructor. So if you want to implement the copy constructor, you'd better not take the argument by copy, because this would call the copy constructor while invoking it, leading to an endless recursion. You can easily try this yourself:
struct tester {
tester(tester) {std::cout << "inside of erroneous copy ctor\n";}
};
int main()
{
tester t1;
std::cout << "about to call erroneous copy ctor\n";
tester t2(t1);
std::cout << "done with call erroneous copy ctor\n";
return 0;
}
That program should only ever write one line and then blow the stack.
Note: As Dennis points out in his comment, actually this program is not guaranteed to compile, so, depending on your compiler, you might not really be able to try it.
Bottom line: A copy constructor should take its argument by reference, because taking it per copy would require the copy constructor.
That leaves the question of why it is const T& and not simply T&? In fact, there are two reasons for that.
The logical reason is that, when you invoke the copy constructor, you do not expect the object copied from to change. In C++, if you want to express that something is immutable, you use const. This tells users that they can safely pass their precious objects to your copy constructor, because it won't do anything with it except read from it. As a nice side effect, if you implement the copy constructor and accidentally try to write to the object, the compiler throws an error message at you, reminding you of the promise made to the caller.
The other reason is that you cannot bind temporary objects to non-const references, you can only bind them to const references. A temporary object is, for example, what a function might return:
struct tester {
tester(tester& rhs) {std::cout << "inside of erroneous copy ctor\n";}
};
tester void f()
{
tester t;
return t;
}
When f() is called, a tester object is created inside, and a copy of it is then returned to the caller, which might then put it into another copy:
tester my_t = f(); // won't compile
The problem is that f() returns a temporary object, and in order to call the copy constructor, this temporary would need to bind to the rhs argument of tester's copy constructor, which is a non-const reference. But you cannot bind a temporary object to a non-const reference, so that code won't compile.
While you can work around this if you want (just don't copy the temporary, but bind it to a const reference instead, which extends the temporary's lifetime to the end of the reference's lifetime: const tester& my_t = f()), people expect to be able to copy temporaries of your type.
Bottom line: A copy constructor should take its argument by const reference, because otherwise users might not be willing or able to use it.
Here's one more fact: In the next C++ standard, you can overload functions for temporary objects, so-called rvalues. So you can have a special copy constructor that takes temporary objects overloading the "normal" copy constructor. If you have a compiler that already supports this new feature, you can try it out:
struct tester {
tester(const tester& rhs) { std::cout << "common copy ctor\n"; }
tester( tester&& rhs) { std::cout << "copy ctor for rvalues\n"; }
};
When you use the above code to invoke our f()
tester my_t = f();
the new copy constructor for rvalues should be called when the temporary object returned by the call to f() is copied to my_t and the regular copy constructor might be called in order to copy the t object from inside of f() to the returned temporary. (Note: you might have to disable your compiler's optimization in order to see this, as the compiler is allowed to optimize away all the copying.)
So what can you with this? Well, when you copy an rvalue, you know that the object copied from is going to be destroyed after the call to the copy constructor, so the copy constructor taking an rvalue (T&&) could just steal the values from the argument instead of copying them. Since the object is going to be destroyed anyway, nobody is going to notice.
For some classes (for example, for string classes), moving the value from one object to another could be much cheaper than copying them.
if I understood your question correctly, to avoid making copies/calling constructor of object.
void function(const T&); // does not create new T
void function(T&); // does not create newT, however T must be modifiable (lvalue)
void function(T); // creates new T
for simple types creating new copy is trivial (and often optimized away by compiler).
For complex object, creating new copy may be very expensive.
Hence you pass it by reference.
https://isocpp.org/wiki/faq/references
https://isocpp.org/wiki/faq/ctors
if you are asking why can not do the following:
struct type {
type(type);
};
Is because this would lead to infinite recursion, since constructor depends on itself
you can do this however
struct type {
type(type, int);
};
since this constructor is different from synthesized type(const type&)
http://en.wikipedia.org/wiki/Copy_constructor
In addition to #aaa's answer, I will try to answer the const part. The const part simply means that the object you are passing logically does not change. This makes sense, because when a copy constructor is called with a Date object argument d, d should not be modified at all!
You can remove the const and your code will still work the same way. However, const provides the additional security that you can never modify the variable marked as const. In your case, this means you can not call any of the non-const method of Date. This is enforced by the compiler at compile-time.
Historically this is the reason for introducing references to the language. Here's an explanation:
In C you can pass values to parameters by value (void f(struct custom_type i)) or by pointer (void g(struct custom_type* i)).
With POD values (int, char, etc.) passing by value is not a problem, but if you are looking at complex structures, then the stack grows too quickly by placing entire structures on stack for function calls. That is why in C you tend to pass structures as parameters by pointer, even if the function doesn't modify them.
In C++ there are cases where neither option worked:
passing by pointers involves a counter-intuitive syntax for operators (if you define operator + for a class custom_type writing custom_type a, b, c; a = &b + &c; is counterintuitive as a doesn't get assigned the sum of the addresses. Furthermore if you wanted to be able to assign the sum of the values to a and the sum of the addresses to a, you would have to somehow differentiate between the cases, by syntax).
passing by value is impossible or undesired in the case of copy constructors. In your case, if you have Date(Date d) {} and assignment Date a; Date b(a); what you get is that a copy of a is created just to be passed as a parameter to the constructor of b. This leads to infinite recursion, as creating a copy of a to pass as a parameter involves is the same as Date d = a; b = Date(d);.
For these reasons (and there may have been others) a decision was made to create references: data types that looks syntactically like a value type, but behave like pointers (that is, it points to the value of another variable, but you access it like a variable, not like a pointer).
Regarding the reason why you need const in the declaration, it is so that your constructor will accept temporary objects. As you cannot modify the value of a temporary references if your constructor doesn't accept const& you can only use the copy constructor for non-const stable objects.
That is, if you have:
class Date
{
public:
Date(Date& other); // non-const reference
...
you can write:
Date a;
Date b = a;
but not:
Date someFunction() { return Date(xxx); }
Date a = someFunction(); // someFunction returns a temporary object
neither:
const Date someImportantDate;
Date a = someImportantDate; // cannot pass const value to non-const