Understanding how to use simple objects in c++ - c++

I have this following code that I must follow:
#include <iostream>
using namespace std;
class T {
public:
T() {}
};
class S {
public:
static int i;
S() { i++; }
S(int unused) { i += 2; }
S(T unused) { i += 3; }
};
int S::i = 0;
S f(S unused)
{
return 0;
}
S g(S& unused)
{
return 1;
}
int main()
{
cout << S::i << "\n";
S s1, s2(2);
cout << S::i << "\n";
T t;
cout << S::i << "\n";
S s3(t);
cout << S::i << "\n";
f(t);
cout << S::i << "\n";
g(s1);
cout << S::i << "\n";
}
From following every declaration and instantiation in the main method, I can follow the output as follows:
0
3
3
6
6
6
I am correct until:
0
3
3
6
But the last two numbers that will be outputted are:
11
13
I am unsure what exactly f(t) and g(s1) do? I am unable to follow how they are changing the value of i.
What do these two statements do?

Both f() and g() are declared to return a value of type S but they actually do a return with an integer value.
So what actually happens is that a temporary value of type S is automatically created from the integer using the conversion constructor S(int unused). That function increments S::i by 2.
Also f() takes as argument a value of type S, but it is calld with a value of type T. Hence, a temporary value of type S is automatically created by the compiler, using the conversion constructor S(T unused). That function increments S::i by 3.

Related

How to perfectly forward `*this` object inside member function

Is it possible to perfectly forward *this object inside member functions? If yes, then how can we do it? If no, then why not, and what alternatives do we have to achieve the same effect.
Please see the code snippet below to understand the question better.
class Experiment {
public:
double i, j;
Experiment(double p_i = 0, double p_j = 0) : i(p_i), j(p_j) {}
double sum() { return i + j + someConstant(); }
double someConstant() && { return 10; }
double someConstant() & { return 100; }
};
int main() {
Experiment E(3, 5);
std::cout << std::move(E).sum() << "\n"; // prints: 108
std::cout << E.sum() << "\n"; // prints: 108
}
This output seems expected if we consider that *this object inside the member function double sum() is always either an lvalue or xvalue (thus a glvalue) . Please confirm if this is true or not.
How can we perfectly forward *this object to the member function call someConstant() inside the double sum() member function?
I tried using std::forward as follows:
double sum() {
return i + j + std::forward<decltype(*this)>(*this).someConstant();
}
But this did not have any effect, and double someConstant() & overload is the one always being called.
This is not possible in C++11 without overloading sum for & and && qualifiers. (In which case you can determine the value category from the qualifier of the particular overload.)
*this is, just like the result of any indirection, a lvalue, and is also what an implicit member function call is called on.
This will be fixed in C++23 via introduction of an explicit object parameter for which usual forwarding can be applied: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html
One would think that std::forward() would preserve lvalue references but it doesn't in non-template contexts, as the example below shows.
Both call_f()& and call_f()&& call f()&&. std::forward<Experiment>(*this) in a non-template function returns an rvalue reference regardless of the value category of the argument.
Note how this works differently from a template function, member or not (I made the member function static because it receives a "this reference" as an explicit parameter) . Both forward lvalue references "properly" (the last 4 calls).
#include<iostream>
#include<utility>
#include<string>
struct Experiment
{
public:
std::string f()&& { return "f()&&"; }
std::string f()& { return "f()&"; }
std::string call_f()&& { std::cout << "call_f()&& "; return std::forward<Experiment>(*this).f(); }
// I need this function because it is not a template function
std::string call_f()& { std::cout << "call_f()& "; return std::forward<Experiment>(*this).f(); }
template<class T = Experiment>
static std::string E_t_call_f(T&& t) { std::cout << "E_t_call_f(T&& t) "; return std::forward<T>(t).f(); }
};
template<class T>
std::string t_call_f(T&& t) { std::cout << "t_call_f(T&& t) "; return std::forward<T>(t).f(); }
int main()
{
Experiment E;
std::cout << "E.f(): " << E.f() << '\n';
std::cout << "move(E).f(): " << std::move(E).f() << '\n';
std::cout << '\n';
std::cout << "E.call_f(): " << E.call_f() << '\n';
std::cout << "move(E).call_f(): " << std::move(E).call_f() << '\n';
std::cout << '\n';
std::cout << "t_call_f(E): " << t_call_f(E) << '\n';
std::cout << "t_call_f(std::move(E)): " << t_call_f(std::move(E)) << '\n';
std::cout << '\n';
std::cout << "E::E_t_call_f(E): " << Experiment::E_t_call_f(E) << '\n';
std::cout << "E::E_t_call_f(std::move(E)): " << Experiment::E_t_call_f(std::move(E)) << '\n';
}
In the resulting output it is the third line that's surprising: The type of std::forward<Experiment>(*this) for an lvalue reference to *this is an rvalue reference.
E.f(): f()&
move(E).f(): f()&&
call_f()& E.call_f(): f()&&
call_f()&& move(E).call_f(): f()&&
t_call_f(T&& t) t_call_f(E): f()&
t_call_f(T&& t) t_call_f(std::move(E)): f()&&
E_t_call_f(T&& t) E::E_t_call_f(E): f()&
E_t_call_f(T&& t) E::E_t_call_f(std::move(E)): f()&&

How to initialize a const reference member to another member (std vector) in C++ initializer list

I did the following as a cheap way to allow read-only access to a member container _numbers via numbers:
class Foo {
Foo() : _numbers({}), numbers(_numbers) {
// some code that populates `numbers` via `numbers.push_back(...)`
}
private:
std::vector<int> _numbers;
public:
const std::vector<int>& numbers;
}
However, doing so I see that numbers is empty, while in other cases it will contain the same elements as _numbers.
To be more precise, it seems to be undefined behavior.
In my real example (of which this a simplified version) I have multiple reference-container pairs with this scheme, where the populated data is visible in the const-reference member for some pairs, and for some it is not.
Any idea whats wrong with this? Any help is deeply appreciated.
EDIT Here is a minimal working example:
#include <vector>
struct Foo2 {
public:
const int max1;
const int center1;
Foo2(const int max1_);
private:
std::vector<int> _numbers1, _numbers2;
public:
const std::vector<int>& numbers1, numbers2;
};
Foo2::Foo2(const int max1_)
: max1(max1_), center1(max1_/2),
_numbers1({}), _numbers2({}),
numbers1(_numbers1),
numbers2(_numbers2)
{
cout << max1 << endl;
for (int i=0; i<center1; i++) {
_numbers1.push_back(i);
cout << "A: " << i << endl;
}
for (int i=center1; i<max1; i++) {
_numbers2.push_back(i);
cout << "B: " << i << endl;
}
for (int i: numbers1) {
cout << "A: " << i << endl;
}
for (int i: numbers2) {
cout << "B: " << i << endl;
}
}
which gives the following Output when initializing Foo2 f(8):
8
A: 0
A: 1
A: 2
A: 3
B: 4
B: 5
B: 6
B: 7
A: 0
A: 1
A: 2
A: 3
i.e. numbers2 does not see the contents of _numbers2 while for numbers1 it seems to work.
const vector<int>& numbers1, numbers2; — Here, only the first variable is a reference. You need & before the second variable to make it a reference as well. Then the code should work.
But I have to say that what you're doing is a really bad idea. You're paying for a convenient syntax with memory overhead, non-assignability, and possibly speed overhead.
Use getters instead: const vector<int>& numbers1() const {return _numbers1;}. Yes, you will have to type the extra () every time.
Hmm... The main cause of the problem was given by #HolyBlackCat: numbers2 was not a reference but an independant copy.
But IMHO there is a more fundamental problem. With:
public:
const std::vector<int>& numbers;
You promise the compiler, that once initialized, the vector referenced by numbers will no longer change. Which is a lie, because the underlying vector changes...
Lying to the compiler is a sure path to UB: it will work sometimes, and will suddenly break because the compiler is free to change its actual code so that no changes to _member will be reflected in members.
Possible fixes:
use std::vector<int>& numbers = _numbers; (no const). This one will be fine, but you loose the ability to present a read only reference
get a fully initialized reference when you need it through a getter (i.e. a method):
const std::vector& numbers() {
return _numbers;
}
Again it is fine, provided _number no longer changes after complete initialization of Foo
use a dedicated object, implicitely convertible to a vector that will be fully initialized before being used:
struct Bar {
std::vector<int>_numbers;
Bar(bool first) : Bar(0, first) {};
Bar(int max, bool first) {
cout << max << endl;
int center = max / 2;
if (first) {
for (int i = 0; i < center; i++) {
_numbers.push_back(i);
cout << "A: " << i << endl;
}
}
else {
for (int i = center; i < max; i++) {
_numbers.push_back(i);
cout << "B: " << i << endl;
}
}
}
operator const std::vector<int>& () {
return _numbers;
}
};
struct Foo2 {
public:
const int max1;
const int center1;
Foo2();
Foo2(const int max1_);
private:
Bar _numbers1, _numbers2;
public:
const std::vector<int>& numbers1, &numbers2;
};

boost multiarray as class member is not filled

I'm trying to use boost to create a multidimensional array and I want said array to be a member of some class.
However I find two problems with it:
1 - I need to declare the size of the array with
boost::extents[2][2]
Everytime I want to use the array. Otherwise I get the following error:
a.out: /usr/include/boost/multi_array/base.hpp:136: Referenceboost::detail::multi_array::value_accessor_n<T, NumDims>::access(boost::type<Reference>, boost::detail::multi_array::value_accessor_n<T, NumDims>::index, TPtr, const size_type*, const index*, const index*) const [with Reference = boost::detail::multi_array::sub_array<double, 1ul>; TPtr = double*; T = double; long unsigned int NumDims = 2ul; boost::detail::multi_array::value_accessor_n<T, NumDims>::index = long int; boost::detail::multi_array::multi_array_base::size_type = long unsigned int]: Assertion `size_type(idx - index_bases[0]) < extents[0]' failed.
2 - Ok, maybe this is just part of how multidimensional arrays work in C++ with Boost, I'm going to write my code accepting every function "declares" the array. However, if I do this I find the array is empty.
Here's a snippet of code that reproduces this problem. During the "construction" of the class the array should be filled. However, the line
cout << "Result: " << testing.getArrayMember(0,1) << endl;
outputs "Result: 0".
#include <iostream>
#include "boost/multi_array.hpp"
typedef boost::multi_array<double, 2> dbl_array;
using namespace std;
class TestClass {
public:
dbl_array darray;
TestClass(double x);
void fillArray(double x);
double getArrayMember(int i, int j);
};
TestClass::TestClass(double x) {
dbl_array darray(boost::extents[2][2]);
cout << "Class constructor called" << endl;
fillArray(x);
}
void TestClass::fillArray(double x) {
cout << "Filling array" << endl;
dbl_array darray(boost::extents[2][2]); // Without this line, the code fails at runtime
darray[0][0] = x;
darray[1][0] = 2.0*x;
darray[0][1] = 3.0*x;
darray[1][1] = 4.0*x;
cout << "Array filled" << endl;
}
double TestClass::getArrayMember(int i, int j) {
dbl_array darray(boost::extents[2][2]); // Without this line, the code fails at runtime
return darray[i][j];
}
int main() {
TestClass testing = TestClass(5.0);
// The result is 0 in the end
cout << "Result: " << testing.getArrayMember(0,1) << endl;
return 0;
}
What am I doing wrong here?
Option 1 is to use an initialisation list:
TestClass::TestClass(double x) : darray(boost::extents[2][2]) {
cout << "Class constructor called" << endl;
fillArray(x);
}
Since otherwise the member of the class darray is created using the default constructor and not through your line
dbl_array darray(boost::extents[2][2]);
as you believe.
This is the same answers as given in initialize boost::multi_array in a class
However, I want to add the following bit, which I think it is relevant in this situation:
It might be necessary for you to generate the array after performing some kind of operation in the constructor of your class. You can achieve this using "resize" after the array has been created by the default constructor.
Ie, instead of
TestClass::TestClass(double x) {
dbl_array darray(boost::extents[2][2]);
cout << "Class constructor called" << endl;
fillArray(x);
}
you could have
TestClass::TestClass(double x) {
darray.resize(boost::extents[2][2]);
cout << "Class constructor called" << endl;
fillArray(x);
}

Writing to file With FStream Not Working

I am attempting to make a program where people put in their preferences file what they would want to do for that week. I made a huge if else statement and need help with my else statement. My else statement is fair to the users/members as their list is randomly picked and the file is created. However, the else statement creates the file, but does not write any of the roles to it. Here is the code :
else {
string positions[23] =
{ "Day_Clean" "Dinner_Cook" "Dinner_Cook" "Dinner_Clean" "Dinner_Clean" "HEB_Shop" "Costco_Shop" "Silver_Fridge" "Stove_Micowave" "Appliance_Clean" "LH_Bathrooms" "Laundry_Room" "Upstairs_Commons" "Bikeroom_Entrance_Stairs" "Little_House_Commons" "Porch_Grounds" "Recycling" "Gardening" "Condi_Fridge_Personal_Fridge" "Freezer" "Downstairs_Bathroom_1" "Downstairs_Bathroom_2" "Upstairs_Bathroom" "Big_House_Hallways" };
ofstream randomPrefs;
randomPrefs.open(foo);
int randomPrefloopcount;
do {
int randomPrefs1 = rand() % 25;
randomPrefs << positions[randomPrefs1] << "\n";
randomPrefloopcount++;
} while(randomPrefloopcount <= 24);
randomPrefs.close();
The files are created, but they are all blank. Please help!
As stated by Sam Varshavchik your problem lies between the number of elements in your array and your loop.
Let's suppose your values never change, there is a safer way to declare and use an array like this in c++11.
#include <array>
#include <iostream>
int main()
{
constexpr std::size_t kArraySize{ 3 };
constexpr std::array<const char *, kArraySize> kArray {
"hehe"
, "hehe"
// , "hehe" // this one would work since there is 3 elements defined
// , "hehe" // this one would fail to compile
};
for (auto element : kArray)
{
if (element != nullptr)
{ std::cout << "element: " << element << std::endl; }
else
{ std::cout << "element is null" << std::endl; }
}
}
std::array ensures that values not defined by user will be zero-initialized, in this case it means that they will be nullptr'ed.
Specified in C++11 §8.5/8:
To value-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type without a user-provided
or deleted default constructor, then the object is zero-initialized …,
and if T has a non-trivial default constructor, the object is
default-initialized;
Quote stolen from this post.
Edit, applied to your code it will look like this:
else {
constexpr std::size_t kArraySize{ 23 };
constexpr std::array<const char *, kArraySize> kPositions { "Day_Clean", "Dinner_Cook", "Dinner_Cook", "Dinner_Clean", "Dinner_Clean", "HEB_Shop", "Costco_Shop", "Silver_Fridge", "Stove_Micowave", "Appliance_Clean", "LH_Bathrooms", "Laundry_Room", "Upstairs_Commons", "Bikeroom_Entrance_Stairs", "Little_House_Commons", "Porch_Grounds", "Recycling", "Gardening", "Condi_Fridge_Personal_Fridge", "Freezer", "Downstairs_Bathroom_1", "Downstairs_Bathroom_2", "Upstairs_Bathroom", "Big_House_Hallways" };
ofstream randomPrefs;
randomPrefs.open(foo);
std::size_t maxRandomLoop { 25 };
for (std::size_t i = 0 ; i < maxRandomLoop ; ++i)
{
int randomPrefs1 = rand() % kArraySize;
if (kPositions[randomPrefs1] != nullptr)
{ randomPrefs << kPositions[randomPrefs1] << "\n"; }
}
randomPrefs.close();
}
Re-edited, you forgot the commas in your array.
A simple program to verify a concept:
#include <iostream>
int main()
{
static const char *tokens[] = {"Tory" "Grant"};
static const char *mythbusters[] = {"Adam", "Jamie"};
// Print out the quantity of elements:
std::cout << "Elements in tokens: " << (sizeof(tokens) / sizeof(tokens[0])) << "\n";
std::cout << "Elements in mythbusters: "
<< (sizeof(mythbusters) / sizeof(mythbusters[0]))
<< "\n";
return 0;
}
This will show you the difference between concatenation of string literals and specifying more than one literal.
Edit: Added '*' before tokens and mythbusters.

Why this data member is initialized? [duplicate]

This question already has answers here:
Uninitialized values being initialized?
(7 answers)
Closed 8 years ago.
I'm doing some testing...
Firstly I post my source code
the .h file
class Complex{
private:
int r = 0;//initializer
int i ;
public:
Complex(int , int I = 0);
Complex();
void print();
void set(int, int I = 1);
static void print_count();
static int count;
};
the .cpp file
#include <iostream>
#include "complex.h"
int Complex::count = 1;
Complex::Complex(int R , int I){
r = R;
i = I;
count++;
std::cout << "constructing Complex object...count is " << Complex::count << std::endl;
}
Complex::Complex(){//default constructor
std::cout << "default constructor is called..." << std::endl;
}
void Complex::print(){
std::cout << "r = " << r << ';' << "i = " << i << std::endl;
return;
}
void Complex::set(int R, int I /*= 2*/){//will be "redefaulting", an error
r = R;
i = I;
return;
}
void Complex::print_count(){//static
Complex::count = -1;//jsut for signaling...
std::cout << "count is " << count << std::endl;
return;
}
the main function
#include <iostream>
#include "complex.h"
int main(){
Complex d;//using default constructor
d.print();
/*Complex c(4, 5);*/
Complex c(4);
//c.print();
/*c.set(2, 3)*/
c.print();
c.set(2 );
c.print();
std::cout << "count is " << c.count << std::endl;//c can access member data
c.print_count();
c.count++;//
return 0;
}
consider the Complex object d constructed with default ctor
because the data member r is initialized using with 0, when executing d.print(),
r is expected to be 0
and i isn't, so I expected it to be garbage value
but when I'm testing, one strange thing happens.
if I eliminate this and the following lines of code in the main file:
std::cout << "count is " << c.count << std::endl;//c can access member data
then d.print() will give the value of i as 32767 on my system, which I guess it's a garbage value;
but once that line is added, d.print() just give i's value to 0 on my system.
I don't get it. I hasn't set, modiify or initialize i's value, why should it be 0?
or, it is also a garbage value?
or, calling one of those function corrupts the value of i?
how is the thing run behind the scene here?
thx for helping.
0 is just as garbage value as any other. Don't make the mistake of thinking otherwise.
Formally, reading an uninitialized variable is undefined behavior, so there's no point in wondering about it: just fix it by initializing the variable properly.