Order of function calls when creating an object of a class [duplicate] - c++

This question already has answers here:
Are multiple mutations within initializer lists undefined behavior?
(2 answers)
std::initializer_list and order of evaluation of the elements [duplicate]
(1 answer)
Order of evaluation in initializer_list c++11
(1 answer)
Closed 11 days ago.
[C++17]
I have a class:
class A
{
int a;
int b;
public:
A(int a, int b) : a{ a }, b{ b } { }
};
and two functions:
int get_a() { return 1; }
int get_b() { return 2; }
Now I construct an object:
A a{ get_a(), get_b() };
The question: is it guaranteed for this case that the order of function evaluation is always get_a and then get_b?

This is called list-initialization.
From cppreference:
Every initializer clause is sequenced before any initializer clause that follows it in the braced-init-list. This is in contrast with the arguments of a function call expression, which are unsequenced(until C++17) indeterminately sequenced(since C++17).
Therefore, then answer is yes, get_a() will always be sequenced before get_b().

Related

constexpr and mutable member and implicit copy-ctor

The following code compiles in clang 7+, but not in 5 & 6 (with c++17 and c++14).
The problem for clang 5 and 6 seems to be that the implicit copy ctor reads from the mutable member x.
Can anybody tell me, if the whole construction is standard-compliant (c++17), or if the program is ill-formed? Or was there a change in the standard regarding the implicit copy-ctor which might not be implemented in the earlier clang versions?
struct Foo {
int a;
mutable int x{};
constexpr Foo() : a(0) {}
//constexpr Foo(const Foo& other) : a(other.a) {} // <- with this line it works on Clang 5 & 6, too
};
struct FooFactory {
static constexpr auto create() {
auto f = Foo{};
return f;
}
};
int main() {
constexpr Foo f = FooFactory::create();
++f.x;
}
Live code here.
This is a well-formed C++17 program. A constexpr function can of course read (and write) non-constant variables:
constexpr int f(int i) {
int j=i;
++j;
return i+j; // neither is a constant expression
}
The rule is that anything examined in a constant expression must either be a constant or have its lifetime begun during the expression’s evaluation. In your case, the lifetime of create’s f.x plainly begins within the evaluation of the constant expression that is the initialization of main’s f. It is true, however, that no Foo object can be copied by a constant expression that does not also create that object, whether or not it is constexpr.
The only other candidate problem is if the copy constructor were not constexpr, but those requirements are very weak. The only relevant ones are that every (non-variant) member be initialized, which is certainly satisfied, and that it be usable in at least one constant expression, which has been demonstrated.
The code is ill-formed. For the reference, here is simplified code, which fails on all compilers:
struct Foo {
int a;
mutable int x{};
constexpr Foo() : a(0) {}
};
int main() {
constexpr Foo f;
constexpr Foo f1 = f;
}
As per [expr.const] 7.7,
A variable is usable in constant expressions after its initializing
declaration is encountered if
it is a constexpr variable,
or ... (3.5) a non-mutable
subobject or reference member of any of the above.
This disqualifies default copy constructors.

making a class Name_class and storing two data types in a single vector [duplicate]

This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 3 years ago.
i don't know the meaning of
Name_value(std::string n, int v)
:name(n), value(v) { }
how do these two lines work?
#include "std_library_facilities.h"
void error(std::string b)
{
throw std::runtime_error(b);
}
class Name_value
{
public:
std::string name;
int value;
Name_value(std::string n, int v)
:name(n), value(v) { }
};
int main()
{
}
There are no vectors involved here; what you see is the declaration of a class Name_value and its constructor Name_value::Name_value(std::string, int).
Constructors are a really basic thing that you're going to have to understand before you do anything in C++.
A constructor is a special class member that sets up a new object of that class type. In this case, the constructor 's definition (declared inline in the class definition)
Name_value(std::string n, int v):
name(n), value(v) { }
sets any new Name_value object's name member to the value of n and it's value member to v
So, if your main contains something like this
int main()
{
Name_value n ("foo", 8);
}
Then n.name would be set to a std::string containing "foo" and n.value would be set to 8.
Name_value(std::string n, int v) is a constructor for Name_value taking two arguments (n and v).
: name(n), value(v) is the constructors initialization list where you initialize class member variables. In this case, the member name is initialized from n and value is initialized from v.
The { } bit is the body of the constructor - which is empty because nothing except initialization (which has already been done) needs to be done for this constructor.

why default initialization using parentheses is not permissible in c++? [duplicate]

This question already has an answer here:
Why can in-class initializers only use = or {}? [duplicate]
(1 answer)
Closed 5 years ago.
This is the example from Effective modern c++.
class Widget {
…
private:
int x{ 0 }; // fine, x's default value is 0
int y = 0; // also fine
int z(0); // error!
};
direct initialization using ()
Inside the class treats the below
int z(0);
As a function as and expects parameter .As result error
Expected parameter declarator
alternatively can be done
class Widget {
private:
int x{ 0 };
int y = 0;
int z;
public:
Widget():z(0){}
};

C++ - lvalue required as left operand of assignment [duplicate]

This question already has answers here:
Function returning struct as LValue
(4 answers)
Closed 5 years ago.
Consider the following code:
#include <iostream>
using namespace std;
class X
{
int i;
public:
X(int ii = 0);
};
X::X(int ii) { i = ii; }
int a;
X f1() { return X(); }
int f2() { return a; }
int main() {
f1() = X(1);
f2() = 3;
}
If you try to run it, you get
error: lvalue required as left operand of assignment
on line 17, therefore
f1()
is considered a lvalue, while
f2()
is not. An explanation would be of great help of how things work would be of great help.
f1() is considered a lvalue
No, what f1 returns is still an rvalue (same as f2; more precisely it's a prvalue). But for class type, f1() = X(1); is just interpreted as f1().operator=(X(1));, which is pretty fine even though it might not make much sense; the temporary object returned by f1() will be destroyed soon. In short, you could call member functions on an rvalue with class type.
On the other hand, the similar behavior for built-in type is forbidden directly; assignment to such temporary doesn't make sense at all. That's why the compiler complains that it's not an lvalue.
f1() returns an rvalue. You have to return a reference (lvalue) to allow you to do this assignment
Change
int f2() { return a; }
to
int& f2() { return a; }
^
f1() returns rvalue but as instance of class f1() = X(1); calls assignment operator of class f1().operator=(X(1)); which is alright.
Read more about value categories here.

Why is the default constructor the only one being used? [duplicate]

This question already has answers here:
Copy constructor elision?
(2 answers)
Closed 8 years ago.
I am triying to see when each method is called in this example:
#include <iostream>
using namespace std;
class A {
public:
int x;
A(int x) : x(x) {cout<<"default ctor"<<endl;}
A(const A& a) : x(a.x) {cout<<"copy ctor"<<endl;}
A& operator =(const A& a) {cout<<"assignment op"<<endl;x=a.x;return *this;}
};
A f() { return A(5); }
int main() {
A a = f();
}
I expected the copy constructor to be called with the sentence return A(5) because as long as I know when an object is returned a temporary copy is created and returned. And also, in the sentence A a = f() I would expect the copy constructor to be called too because a is being initialized given another A object.
Why is default ctor being printed?
Two optimizations come into play here. Return Value Optimization (RVO)
And Copy Elision will merge f()'s return value directly into the destination variable via initialization. So this code:
A f() { return A(5); }
A a = f();
Optimizes to essentially:
A a(5);
Because c++ compilers are allowed to skip the operator= in cases of
A a = A();
A b = A(a);
and use constructors directly.
They are also allowed to perform Return Value Optimization for copy elision.
So in the end you have essentially A a(5);