I found this example interview question and would like some help understanding it:
#include <iostream>
class A
{
public:
A(int n = 0)
: m_n(n)
{
++m_ctor1_calls;
}
A(const A& a)
: m_n(a.m_n)
{
++m_copy_ctor_calls;
}
public:
static int m_ctor1_calls;
static int m_copy_ctor_calls;
private:
int m_n;
};
int A::m_ctor1_calls = 0;
int A::m_copy_ctor_calls = 0;
void f(const A &a1, const A &a2 = A())
{
}
int main()
{
A a(2), b = 5;
const A c(a), &d = c, e = b;
std::cout << A::m_ctor1_calls << A::m_copy_ctor_calls;
b = d;
A *p = new A(c), *q = &a;
std::cout << A::m_copy_ctor_calls;
delete p;
f(3);
std::cout << A::m_ctor1_calls << A::m_copy_ctor_calls << std::endl;
return 0;
}
The way I understand it, the first line of main creates two new objects, resulting in 2 calls to the constructor. In the second line, I see that they use the copy constructor for c(a) and e = b. The copy constructor isn't used for &d = c because it is only referencing c is that right? Also one thing I don't understand is that if the copy constructor requires a reference, how come an object is being passed into it instead of a reference to the object? The parts after with pointers are really confusing to me. Can someone provide some insight?
Thanks!
The copy constructor isn't used for &d = c because it is only
referencing c is that right?
Yes. d becomes an alias for c.
Also one thing I don't understand is that if the copy constructor
requires a reference, how come an object is being passed into it
instead of a reference to the object?
An object passed into a function taking a reference is automatically "converted" into a reference. The parameter is now an alias for the passed-in object.
The parts after with pointers are really confusing to me. Can someone
provide some insight?
p points to a newly allocated A object, copied from c. q points to a. (1 copy constructor). Then p is deleted.
f(3) gets fun. It constructs a temporary A initialized with 3 to bind to a1. a2 gets a temporary default constructed A. After f(3) finishes, these two temporaries are destroyed.
End of the function, and the remaining instances of A are destroyed.
Outside of an interview, you can stick this code in an IDE and step through it with a debugger.
In case you were wondering, here is the output (with spaces added):
2 2 3 4 3
Related
It is said that constructor doesnot return anything.But if constructor doesnot return anything, then how do this code segment works:
*this=classname{args};.
I hope someone could shed me some light on whats actually going under the hood.
A complete code:
#include <iostream>
using namespace std;
class hell {
private:
int a{}, b{};
public:
hell(int _a = 7, int _b = 8) : a{ _a }, b{ _b } {}
void print() {
cout << a << endl << b << endl;
}
void change() {
*this = hell(4, 5);
}
};
int main() {
hell h;
h.print();
h.change();
h.print();
return 0;
}
The statement
*this = hell(4, 6);
does two things:
First it create a temporary and unnamed object of the class hell, initialized using the values you use to pass to a suitable constructor.
Then that temporary and unnamed object is copy-assigned to the object pointed to by this.
It's somewhat similar to this:
{
hell temporary_object(4, 5); // Create a temporary object
*this = temporary_object; // Copy the temporary object to *this
}
Your question must be about this line:
*this = hell(4,5);
This might look like a function call, calling the constructor function. But this is not a function call. This is (a particular) syntax for creating a new hell object, a temporary object. This is slightly outdated syntax, modern C++ prefers:
*this = hell{4, 5};
but it's the same thing.
This does call the constructor, but only as part of constructing a new object.
Once the temporary object gets constructed it gets assigned to *this. The End.
For better intuition, constructor can be called "initializator". This reveals more of it's main purpose. The constructor initializes object rather then creates. So the instance of the object is already present in the memory when the constructor is called. All it does is initializing it.
I came across a piece of code that had structs and I am now thoroughly confused about how automatically the constructor of the struct is being called. I made a dummy code just to understand the concept. For example,
struct obj {
int a = 0, b = 2;
obj (int aa) {
a = aa;
}
obj (int aa, int bb) {
a = aa;
b = bb;
}
int getSum () {
return a+b;
}
};
void calcSum (obj o) {
cout << o.getSum() << endl;
}
int main()
{
calcSum(5);
return 0;
}
This does print 7. I believe that the single argument constructor of struct obj is automatically being called. If so, how can I make it automatically call the double argument constructor? I am unable to do so.
What is the name of this functionality?
Also please guide me to some good articles as I was unable to find any.
You can use a braced initialization list to invoke the constructor:
calcSum({5, 3});
A somewhat broad term for this feature of C++ is called "implicit conversion". If the type of the object being "assigned to" (or constructed, which in this case is a function parameter) does not match the type of the object being "assigned from", C++ has a long, long list of rules of implicit conversions that can be used to convert one type to another.
One of these rules involves a comma-separated list of values in braces. If it is specified for an object with an explicit constructor, the constructor get used to construct the object.
Note that this also invokes the same constructor as in the original code:
calcSum({5});
A constructor with one parameter does not need braces to be implicitly invoked.
I am struggling to understand the difference in behaviour of a raw pointer and a unique_ptr. I have class A with a variable x and class B with a pointer to an instance of A:
class A
{
public:
int x;
};
A::A(int y) : x(y)
{
}
class B
{
public:
B(A &);
A *p;
};
B::B(A &a)
{
p = &a;
}
This behaves as I would expect:
int main()
{
A a(2);
B b(a);
cout << a.x << " " << b.p->x << endl;
a.x = 4;
cout << a.x << " " << b.p->x << endl;
}
gives
2 2
4 4
Changing the raw pointer to a std::unique_ptr gives a different result:
class A
{
public:
int x;
};
A::A(int y) : x(y)
{
}
class B
{
public:
B(A &);
std::unique_ptr<A> p;
};
B::B(A &a)
{
p = std::make_unique<A>(a);
}
gives
2 2
4 2
Have I fundamentally misunderstood something about unique_ptrs?
make_unique creates a fresh object, one that that unique_pt has exclusive access to. So in the second example you have two objects, not one and when you set change the value of a.x in the first object it doesn't effect the other object held by the unique_ptr.
A unique pointer needs to own whatever it points to. Your code can be made to work - just substituting unique_ptr type and leaving everything else unchanged (no make_unique). But it will have undefined behavior, since you’ll create a unique pointer to an object that is owned elsewhere.
To compare apples to apples, the raw pointer code should read p=new A(a);. That’s what make_unique does.
Try reading the following expression from the smart pointer version:
std::make_unique<A>(a);
"make a unique A from a" (no mention of pointers!)
The result is a unique_ptr, but when reading the expression, read it as making (an object whose type is) the template parameter. The function parameters are parameters to the constructor. In this case, you are making an A object from an A object, which pulls in the copy constructor.
Once you understand that the smart pointer version is making a new A object (and your raw pointer version does not), your results should make sense.
The "unique" in "unique A" might be tricky to understand. Think of it as an object that no one else can lay claim to. It might be a copy of another object, but, taking the role of the unique_ptr, it is your copy, your responsibility to clean up after, and no one else's. Your preciousss, which you will not share (c.f. std::make_shared).
Note that a local variable (like the a in the main function) is the responsibility of the compiler, so it is ineligible to be the object to which a unique_ptr points (or any smart pointer, for that matter).
I have two methods to create an instance for a pointer.
But one of them will fail.
class A {
public:
int num;
};
void testPointer1(A* a){
a = new A();
a->num = 10;
}
A* testPointer2(){
A* a = new A();
a->num = 10;
return a;
}
void testPointer() {
A* a1 = NULL;
testPointer1(a1); // this one fails
//cout << a1->num << endl; // segmentation fault
A* a2 = NULL;
a2 = testPointer2();
cout << a2->num << endl;
}
why is testPointer1 wrong?
The syntax is valid, but it doesn't do what you want because testPointer1() is operating on a copy of the pointer, not the actual pointer itself. So when you assign the address to the newly allocated object, it gets assigned to the copy, not to the original a1 pointer.
Because of this, the address is lost and you get a memory leak. Also, since the original a1 pointer was never modified in the first place, you attempted to dereference a null pointer, which is a bad thing.
I'd say testPointer2() is the better way to do it, but if you want testPointer1() to work, try this:
void testPointer1(A*& a)
{
a = new A();
a->num = 10;
}
The parameter type indicates "a reference to a pointer to A." That way, instead of a copy of the pointer being passed, a reference to the original pointer will be passed. A C++ reference is an alias to another object. So whatever you do on the alias, it gets performed on the original object.
Extra notes:
Note that the parentheses in new A(); are actually significant and their presence or absence makes a difference.
Also note that you must manually delete all new'ed objects after you're done with them, or you will get a leak. Typically you would wrap the pointer in its own class and implement RAII or use a smart pointer such as Boost's smart pointers or auto_ptr, for proper memory management and exception safety.
If you're going to set the value of num on initialization, why not create a constructor?
class A
{
public:
A(int n) : num(n) {}
int GetNum() const { return num; }
private:
int num;
};
void testPointer1(A*& a)
{
a = new A(10);
}
A* testPointer2()
{
return new A(10);
}
// auto_ptr example, see link in second note above
std::auto_ptr<A> testPointer3()
{
return auto_ptr<A>(new A(10));
}
The testPointer1 functions works on a copy of the provided pointer : modifications to a in testPointer1 are not reflected to the caller.
It's exactly like in this simpler example :
void testInt1(int i)
{
i++;
}
void testInt()
{
int i = 0;
testInt1(i);
// i is still 0
}
If you want the change in testInt1 to be reflected to the caller, you have to pass either a pointer or reference to i (and not just the value of i). The same solution can be applied to your specific case, though one could argue that pointers to pointer and references to pointer are not really a best practice.
Is this homework ?
This seems to be obvious:
formal parameters are saved on the stack & restored after method/function call.
then whatever f(type x), manipulating x inside the function/method won't change it's value outside of the function.
even if type is a pointer type.
the only way to make x change inside a function is to tell it is modifiable through references or pointer to type.
in your case :
A* a1 =NULL
call to your method won't change value of a1 outside of testPointer1
so a1 will still be NULL after the call.
I have the following code which doesn't compile. The compiler error is:
"error: no matching function to call B::B(B)",
candidates are B::B(B&) B::B(int)"
The code compiles under either of the following two conditions:
Uncommenting the function B(const B&)
change 'main' to the following
int main()
{
A a;
B b0;
B b1 = b0;
return 0;
}
If I do 1, the code compiles, but from the output it says it's calling the 'non const copy constructor'.
Can anyone tell me what's going on here?
using namespace std;
class B
{
public:
int k;
B()
{
cout<<"B()"<<endl;
}
B(int k)
{
cout<<"B(int)"<<endl;
this->k = k;
}
/*B(const B& rhs) {
cout<<"Copy constructor"<<endl;
k = rhs.k;
}*/
B(B& rhs)
{
cout<<"non const Copy constructor"<<endl;
k = rhs.k;
}
B operator=(B& rhs)
{
cout<<"assign operator"<<endl;
k = rhs.k;
return *this;
}
};
class A
{
public:
B get_a(void)
{
B* a = new B(10);
return *a;
}
};
int main()
{
A a;
B b0 = a.get_a(); // was a.just();
B b1 = b0 ;
return 0;
}
I've done some extra reading into this, and as I suspected all along, the reason why this occurs is due to return value optimization. As the Wikipedia article explains, RVO is the allowed mechanism by which compilers are allowed to eliminate temporary objects in the process of assigning them or copying them into permanent variables. Additionally, RVO is one of the few features (if not the only) which are allowed to violate the as-if rule, whereby compilers are only allowed to make optimizations only if they have the same observable behaviours as if the optimization were never made in the first place -- an exemption which is key in explaining the behaviour here (I admittedly only learned of that exemption as I was researching this question, which is why I was also confused initially).
In your case, GCC is smart enough to avoid one of the two copies. To boil your code down to a simpler example
B returnB()
{
B a;
B* b = &a;
return *b;
}
int main()
{
B c = returnB();
return 0;
}
If one follows the standard and does not perform RVO, two copies are made in the process of making c -- the copy of *b into returnB's return value, and the copy of the return value into c itself. In your case, GCC omits the first copy and instead makes only one copy, from *b directly into c. That also explains why B(B&) is called instead of B(const B&) -- since *b (a.k.a. a) is not a temporary value, the compiler doesn't need to use B(const B&) anymore and instead chooses the simpler B(B&) call instead when constructing c (a non-const overload is always automatically preferred over a const overload if the choice exists).
So why does the compiler still give an error if B(const B&) isn't there? That's because your code's syntax must be correct before optimizations (like RVO) can be made. In the above example, returnB() is returning a temporary (according to the C++ syntax rules), so the compiler must see a B(const B&) copy constructor. However, once your code is confirmed to be grammatically correct by the compiler, it then can make the optimization such that B(const B&) is never used anyway.
EDIT: Hat tip to Charles Bailey who found the following in the C++ standard
12.2 [class.temporary]: "Even when the creation of the temporary is avoided,
all the semantic restrictions must be
respected as if the temporary object
was created."
which just reinforces and confirms the need for a copy constructor taking a reference to const when temporaries are to be copied for construction (irrespective of whether or not the constructor is actually used)
Your get_a() function returns an object B, not a reference (but leaks the newly-created B object). Also, for assignments to work as you're doing, you need to make sure your assignment operator and copy constructors are both taking const B& arguments — then B b1 = b0 will work in this case. This works:
class B
{
public:
int k;
B() { cout<<"B()"<<endl; }
B(int k) {
cout<<"B(int)"<<endl;
this->k = k;
}
B(const B& rhs) {
cout<<"non const Copy constructor"<<endl;
k = rhs.k;
}
B operator=(const B& rhs) {
cout<<"assign operator"<<endl;
k = rhs.k;
return *this;
}
};
class A {
public:
B* get_a(void) {
B* a = new B(10);
return a;
}
B get_a2(void) {
B a(10);
return a;
}
};
int main() {
A a;
B b0 = *a.get_a(); // bad: result from get_a() never freed!
B b1 = a.get_a2(); // this works too
return 0;
}
Short explanation: functions that return by value create a temporary object which is treated as constant and therefore cannot be passed to functions accepting by reference, it can only be passed to functions accepting const reference. If you really allocate an object in get_a(), you should really be returning a pointer (so that you remember to delete it, hopefully) or in the worst case - a reference. If you really want to return a copy - create the object on the stack.
Long explanation: To understand why your code doesn't compile if there is only "non-const copy constructor"1, you need to be familiar with the terms lvalue and rvalue. They originally meant that rvalues can only stand on the right side of operator = (assignment) while lvalues can stand also on the left side. Example:
T a, b;
const T ac;
a = b; // a can appear on the left of =
b = a; // so can b => a and b are lvalues in this context
ac = a; // however, ac is const so assignment doesn't make sense<sup>2</sup>, ac is a rvalue
When the compiler is performing overload resolution (finding which overload of a function/method best match the provided arguments) it will allow lvalues to match parameters passed by value3, reference and const reference types. However, it will match rvalues only against value3 and const reference parameters. And that's because in some sense, since rvalues cannot be put on the left side of operator =, they have read-only semantic, and when it shouldn't be allowed to modify them. And when you accept a parameter through non-const reference, it's implied that you'll somehow change this parameter.
The last piece of the puzzle: temporary objects are rvalues. Function returning by value creates a temporary object with very limited lifespan. Because of its limited lifespan it's considered const, and is therefore a rvalue. And this rvalue doesn't match functions with parameters by non-const reference. Examples:
void f_cref(const A& a) { std::cout << "const ref" << std::endl; }
void f_ref(A& a) { std::cout << "non-const ref" << std::endl; }
A geta() { return A(); }
A a;
const A ac;
f_ref(a); // ok, a is a lvalue
f_ref(ac); // error, passing const to non-const - rvalue as lvalue - it's easy to spot here
f_cref(a); // ok, you can always pass non-const to const (lvalues to rvalues)
f_ref(geta()); // error, passing temporary and therefore const object as reference
f_cref(geta()); // ok, temporary as const reference
Now you have all the information to figure out why your code doesn't compile. Copy constructor are like regular functions.
I have oversimplified things a bit, so better, more complete and correct explanation can be found at this excellent Visual C++ Studio Team blog post about rvalue references, which also addresses the new C++ 0x feature "rvalue references"
1 - there's no such thing as non-const copy constructor. The copy constructor accepts const reference, period.
2 - you can probably put const object on the left of = if it has its operator = declared const. But that would be terrible, terrible, nonsensical thing to do.
3 - actually, you wouldn't be able to pass const A by value if A doesn't have a copy constructor - one that accepts const A& that is.
The line B b1 = b0; is the culprit. This line requires calling a copy constructor. You could fix the code by writing B b1(b0) instead, or by defining a copy constructor, which takes a const B&, but not a B&.