0

I meet a course programming problem, which asks me to initialize the A a using passing by reference (initialize the A a in the func). How can I call A's constructor by A's reference?

#include <iostream>
using namespace std;

class A
{
public:
    int x;
    A()
    {
        cout << "default constructor" << endl;
        x = 1;
    }

    A(int x)
    {   
        cout << "constructor with param = "  << x << endl;
        this->x = x;
    }

    ~A() {
        cout << "destructor" << endl;
    }

    void print() {
        cout << x << endl;
    }
};


void fun(A& a)
{
    a.A::A(10); // error!
    return;
}


int main()
{
    A a; 
    fun(a);
    a.print();
    return EXIT_SUCCESS;
}

There is a background of this problem. The teacher want us to replicate the NRVO(named return value optimization) result.

#include <iostream>
using namespace std;

class A
{
public:
    int x;
    A()
    {
        cout << "default constructor" << endl;
        x = 1;
    }

    A(int x)
    {   
        cout << "constructor with param = "  << x << endl;
        this->x = x;
    }

    ~A() {
        cout << "destructor" << endl;
    }

    void print() {
        cout << x << endl;
    }
};

A fun() {
    A a = A(10);
    return a;
}


int main()
{
    A a = fun();
    return EXIT_SUCCESS;
}

default g++ compiler:

constructor with param = 10
destructor

if we close the NRVO: g++ test.cpp -fno-elide-constructors

constructor with param = 10
destructor
destructor
destructor
destructor

The teacher want us to replicate the NRVO(named return value optimization) result by passing by reference.

maplemaple
  • 1,297
  • 6
  • 24
  • Constructor is used to create an object of a class, you cannot call it on an already existing object. Even a constructor cannot be explicitly called. It is implicitly called by the compiler. – Jason May 14 '22 at 06:01
  • @AnoopRana There is a background. The teacher want us to replicate the result of Return Value Optimization. – maplemaple May 14 '22 at 06:02
  • You don't initialize a class object after you've created it. Creation, is initialization. I – Galik May 14 '22 at 06:03
  • Please explain what observable behaviour the program should have. – n. m. could be an AI May 14 '22 at 06:04
  • @Galik In general *"Creation is initialization"* seems incorrect. Especially in C++. You can create an object(in local scope for non-class type object) say by `int i;` which is uninitialized. – Jason May 14 '22 at 06:05
  • @AnoopRana True, but `int` isn't a class object. Class objects are initialized by their constructor, otherwise it's assignment. – Galik May 14 '22 at 06:07
  • @Galik Yes, that is why i wrote "in general" and mentioned "for non-class type object in local scope". – Jason May 14 '22 at 06:08
  • @Galik I've added more backgrounds about RVO. – maplemaple May 14 '22 at 06:10
  • @AnoopRana I've added more backgrounds about RVO. – maplemaple May 14 '22 at 06:10
  • @n.1.8e9-where's-my-sharem. I've added more backgrounds about RVO. – maplemaple May 14 '22 at 06:10
  • @AnoopRana Ah, okay. I see where you're coming from. I was just assuming the context of dealing with class objects. – Galik May 14 '22 at 06:10
  • You appear to be attempting `NRVO` (Named Value Return Optimization) rather than `RVO` (Return Value Optimization). – Galik May 14 '22 at 06:15
  • You need a whole lot more esoteric features of C++ than just passing by reference to replicate (N)RVO. – n. m. could be an AI May 14 '22 at 06:19
  • 2
    Perhaps your teacher wants you to pass a pointer to uninitialized storage and use placement `new` to initialize an object into it from within `fun`? That's _kind of_ what (N)RVO does under the hood. See my answer to [this question](https://stackoverflow.com/questions/48955310/how-does-c-abi-deal-with-rvo-and-nrvo) for a bit more detail. – Miles Budnek May 14 '22 at 06:29

2 Answers2

0

The syntax a.A::A(10); is incorrect.

Constructor is used to create an object of a class, you cannot call it on an already existing object. Even a constructor cannot be explicitly called. It is implicitly called by the compiler.

From general-1.sentence-2:

Constructors do not have names.

Thus, you cannot call a constructor explicitly. The compiler will automatically call the constructor when an object of that class-type is created.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • I see. Thanks. Therefore I cannot use pure c++ syntax to simulate NRVO compiling result right? – maplemaple May 14 '22 at 06:17
  • @maplemaple Starting from C++17, RVO is mandatory. Also, NRVO and RVO are different. Also, i am not entirely sure the objective/aim of your homework. I mean your instructor should have given some more details and context IMO. And yes, you cannot achieve the goal by having the syntax that you currently had(`a.A::A(10);`). – Jason May 14 '22 at 06:19
  • I thought the teacher wanted me to write equivalent c++ code to represent how NRVO works by pass by ref. Maybe he just wants us to explain how it work by pass by ref in high level. – maplemaple May 14 '22 at 06:22
  • @maplemaple I am also curious to see/know how your instructor will simulate this(or expect to simulate this). Or maybe the assignment was just misinterpreted because the lack of details/context. – Jason May 14 '22 at 06:22
  • @maplemaple It's indeed not possible to accurately simulate NRVO with pure C++ syntax. Problem is that NRVO separates the allocation of storage (by caller) and the creation of the object (in the function) and that's possible in C++ only for objects of dynamic storage duration, while the variable in your case has automatic storage. – eerorika May 14 '22 at 10:28
0

You can not, not like this.

A reference always points to an initialized object. So you already failed before you called the function. The "return" argument is already initialized. And you can't initialized an initialized value again, not legally.

You can cheat by calling

std::construct_at(&a, 10);

For it to really reflect NRVO you could have something like this:

void fun(A *a)
{
    std::construct_at(a, 10);
}

union UninitializedA {
    std::byte uninitialized[sizeof(A)];
    A a;
};

int main()
{
    UninitializedA u;
    fun(&u.a);
    u.a.print();
    u.a.~A();
    return EXIT_SUCCESS;
}
Goswin von Brederlow
  • 11,875
  • 2
  • 24
  • 42