initialize reference in initialization list - c++

I was told the reference variable must be initialized in the initialization list, but why this is wrong?
class Foo
{
public:
Foo():x(0) {
y = 1;
}
private:
int& x;
int y;
};
Because 0 is a temporary object? If so, what kind of object can reference be bound? The object which can take an address?
Thanks!

0 is not an lvalue, it's an rvalue. You cannot modify it, but you're trying to bind to a reference where it could be modified.
If you make your reference const, it will work as expected. Consider this:
int& x = 0;
x = 1; // wtf :(
This obviously is a no-go. But const&'s can be bound to temporaries (rvalues):
const int& x = 0;
x = 1; // protected :) [won't compile]
Note that the life-time of the temporary is ended at the completion of the constructor. If you make static-storage for your constant, you'll be safe:
class Foo
{
public:
static const int Zero = 0;
Foo() : x(Zero) // Zero has storage
{
y = 1;
}
private:
const int& x;
int y;
};

Well, you can never change it, 0 can never equal anything other than 0.
try
class Foo
{
public:
Foo(int& a):x(a) {
y = 1;
}
private:
int& x;
int y;
};
Alternatively, you can do this if your reference is constant because then 0 can only ever equal zero

A long lived reference must be bound to an lvalue. Basically, as you so eloquently put it, an object that has a definite address. If they are bound to a temporary the temporary will be destroyed while the reference is still referencing it and the results are undefined.
Short lived const references (local function variables and function arguments) can be bound to temporaries. If they are, the temporary is guaranteed to not be destroyed until the reference goes out of scope.
Demonstration code:
#include <iostream>
class Big {
public:
Big() : living_(true), i_(5) { // This initialization of i is strictly legal but
void *me = this; // the result is undefined.
::std::cerr << "Big constructor called for " << me << "\n";
}
~Big() {
void *me = this;
living_ = false;
::std::cerr << "Big destructor called for " << me << "\n";
}
bool isLiving() const { return living_; }
const int &getIref() const;
const int *getIptr() const;
private:
::std::string s_;
bool living_;
const int &i_;
char stuff[50];
};
const int &Big::getIref() const
{
return i_;
}
const int *Big::getIptr() const
{
return &i_;
}
inline ::std::ostream &operator <<(::std::ostream &os, const Big &b)
{
const void *thisb = &b;
return os << "A " << (b.isLiving() ? "living" : "dead (you're lucky this didn't segfault or worse)")
<< " Big at " << thisb
<< " && b.getIref() == " << b.getIref()
<< " && *b.getIptr() == " << *b.getIptr();
}
class A {
public:
A() : big_(Big()) {}
const Big &getBig() const { return big_; }
private:
const Big &big_;
};
int main(int argc, char *argv[])
{
A a;
const Big &b = Big();
const int &i = 0;
::std::cerr << "a.getBig() == " << a.getBig() << "\n";
::std::cerr << "b == " << b << "\n";
::std::cerr << "i == " << i << "\n";
return 0;
}
And the output:
Big constructor called for 0x7fffebaae420
Big destructor called for 0x7fffebaae420
Big constructor called for 0x7fffebaae4a0
a.getBig() == A living Big at 0x7fffebaae420 && b.getIref() == -341121936 && *b.getIptr() == -341121936
b == A living Big at 0x7fffebaae4a0 && b.getIref() == 0 && *b.getIptr() == 0
i == 0
Big destructor called for 0x7fffebaae4a0

Related

c++: Program crashes with parameter (by value) passed to a lambda

I simplified the code, so pardon my style.
I was wondering what happens to an object that is constructed by a constructor that actually allocates memory, and passed to a lambda by value, when this lambda itself, is being a callback by another thread.
It didn't surprise me to see the program crashes when the destructor is called. This was test#1.
test#2: I removed the "new" and the "delete[]" from c'tor and d'tor of A, and now - it worked fine.
test#3:
I brought the "new" and the "delete[]" back as before, but now I changed every place with "A objA" (by value) into "A& objA", and now, it didn't crash as well.
Now, I can rationalize it by waving my hands but I'd like to understand what really happened here, and for that matter - what would happen if an object that is passed into a lambda by "capture", also ceases to exist.
and last question: is there a good practice or tip what to do (or what to avoid) in such cases?
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
using namespace std::chrono_literals;
class A {
public:
A() : x(1) { ptr = new char[1024]; }
~A() { delete[](ptr); }
int getX() { return x; }
private:
int x = 0;
char* ptr = nullptr;
};
std::function<void(A objA)> myCb;
int myThread()
{
static int counter = 0;
auto a = new A;
while (true) {
std::this_thread::sleep_for(2s);
if (myCb)
myCb(*a);
else
std::cout << "myCb is still NULL: counter = " << counter << std::endl;
if (counter++ == 5)
break;
}
return 0;
}
void registerCallback(std::function<void(A obj)> cb)
{
myCb = cb;
}
int main()
{
std::thread t1(myThread);
std::this_thread::sleep_for(6s);
int val = 5;
registerCallback([&val](A objA) {
std::cout << "here lambda is called with " << objA.getX() << " and " << val << std::endl;
});
val = 6;
std::this_thread::sleep_for(1s);
val = 7;
std::this_thread::sleep_for(1s);
val = 8;
std::this_thread::sleep_for(1s);
t1.join();
}
class A is violating the Rule of 3/5/0, as it does not implement a copy-constructor and/or move-constructor, or a copy-assignment and/or move-assignment operator.
So, when an instance of A is passed around by value, a shallow copy is made that shares the same char* pointer to a single char[] array in memory, and thus the code MAY crash (ie, undefined behavior) when trying to delete[] that same array multiple times.
What you need is a deep copy instead, so that each instance of A allocates its own char[] array, eg:
class A
{
public:
A() : x(1), ptr(new char[1024])
{
std::fill(ptr, ptr + 1024, '\0');
}
A(const A &src) : x(src.x), ptr(new char[1024])
{
std::copy(src.ptr, src.ptr + 1024, ptr);
}
A(A &&src)
: x(src.x), ptr(src.ptr)
{
src.ptr = nullptr;
}
~A()
{
delete[] ptr;
}
A& operator=(A rhs)
{
std::swap(x, rhs.x);
std::swap(ptr, rhs.ptr);
return *this;
}
int getX() const { return x; }
private:
int x;
char* ptr;
};
A simpler way to implement this is to use std::vector instead of new[], since vector is already compliant with the Rule of 3/5/0, and so compiler-generated constructors, destructor, and assignment operators for A will suffice to make copies/moves of the vector for you, eg:
#include <vector>
class A
{
public:
A() : vec(1024, '\0') {}
int getX() const { return x; }
private:
int x = 1;
std::vector<char> vec;
};
You should use unique_ptr. deleting a void* is undefined behavior
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
using namespace std::chrono_literals;
class A {
public:
A() : x(1)
{
ptr = std::make_unique<char[]>(1024);
}
~A()
{
}
int getX() { return x; }
private:
int x = 0;
std::unique_ptr<char[]> ptr = nullptr;
};
std::function<void(A& objA)> myCb;
int myThread()
{
static int counter = 0;
auto a = new A;
while (true) {
std::this_thread::sleep_for(2s);
if (myCb)
myCb(*a);
else
std::cout << "myCb is still NULL: counter = " << counter << std::endl;
if (counter++ == 5)
break;
}
return 0;
}
void registerCallback(std::function<void(A& obj)> cb)
{
myCb = cb;
}
int mymain()
{
std::thread t1(myThread);
std::this_thread::sleep_for(6s);
int val = 5;
registerCallback([&val](A& objA) {
std::cout << "here lambda is called with " << objA.getX() << " and " << val << std::endl;
});
val = 6;
std::this_thread::sleep_for(1s);
val = 7;
std::this_thread::sleep_for(1s);
val = 8;
std::this_thread::sleep_for(1s);
t1.join();
return 0;
}

Why is the scope of object created using new limited? [duplicate]

This question already has answers here:
Do Pointer Parameters Need To Be Passed By Reference
(3 answers)
Closed 3 years ago.
Object made using new operator does not seem to be available outside the scope! Isn't that the whole point of the new operator?
https://ideone.com/DDvo9y - Please check this link to see the result.
#include<iostream>
class myClass
{
private:
int val;
public:
myClass () = delete;
myClass (int val):val{val}{}
int get () const
{
return val;
}
};
bool ifEqualMake (int a, int b, myClass * obj)
{
if (a == b) obj = new myClass (a);
else{
std::cout << "Difference exists: " << a - b << '\n';
obj = new myClass (a + b);
}
std::cout << " Object made with value :" << obj->get () << '\n';
return (a == b);
}
int main ()
{
myClass *obj1 = nullptr;
myClass *obj2 = nullptr;
myClass *obj3 = nullptr;
ifEqualMake (3, 3, obj1);
ifEqualMake (4, 3, obj2);
ifEqualMake (4, 4, obj3);
if(obj1) std::cout << "obj 1 made in heap: " << obj1->get () << '\n';
if(obj2) std::cout << "obj 2 made in heap: " << obj2->get()<<'\n';
if(obj3) std::cout << "obj 3 made in heap: " << obj3->get () << '\n';
delete obj1;
delete obj2;
delete obj3;
return 0;
}
It isn't.
You're confusing the dynamically-allocated object that you created with new, and the pointer that points to it.
The pointer's scope is limited just like any other automatic-storage-duration object.
It looks like you meant to use it as an "out" argument to the function ifEqualMake, perhaps by taking a reference to it rather than a copy. Then alterations to it, such as pointing it to a new object, will be mirrored in the calling scope.
The parameter obj is passed by value, that means it's just a copy of the argument, and any modification on itself inside the function (like obj = new myClass (a);) has nothing to do with the original pointer. In the meanwhile, the object constructed inside the function won't be destroyed.
You might change it to pass-by-reference.
bool
ifEqualMake (int a, int b, myClass *& obj)
// ^
{
...
}
Consider the following function:
void foo(int i) {
i = 4;
}
void bar() {
int j = 0;
foo(j);
std::cout << j << '\n';
}
You would expect bar to print 0, not 4, because foo is assigning to a local variable.
This behaviour does not change with pointers. The following code behaves the same way:
void foo(int* i) {
int temp = 0;
i = &temp;
}
void bar() {
int* j = nullptr;
foo(j);
std::cout << j << '\n';
}
The simplest fix to the code you present is to take the pointer by reference:
void foo(int*& i) {
int temp = 0;
i = &temp;
}
void bar() {
int* j = nullptr;
foo(j);
// j now points to a destroyed object
std::cout << j << '\n';
}

Why is destructor being called more than enough when using an object as key in a multimap

I am using an object as a key in a multimap as follows. I only have 1 instance of class Data: Data d1(1,2).
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Data{
public:
static int counter;
Data(int x = 0, int y = 0):_x(x),_y(y){counter += 1; cout <<"constructor call " << counter << endl;}
virtual ~Data()
{
counter -= 1;
cout <<"calling destructor " << counter << endl;
}
bool operator<(const Data & right) const{
return _x < right._x && _y < right._y;
}
private:
int _x;
int _y;
};
int Data::counter = 0;
int main()
{
multimap<Data, string> m_map;
Data d1(1,2);
m_map.insert(make_pair(d1, "1"));
return 0;
}
In the output the destructor is being called 3 times.
constructor call 1
calling destructor 0
calling destructor -1
calling destructor -2
You have more than one instance.
class Data {
public:
static int counter;
Data(int x = 0, int y = 0) :_x(x), _y(y) { counter += 1; cout << "constructor call " << counter << endl; }
Data(const Data & other) :_x(other._x), _y(other._y) { counter += 1; cout << "copy constructor call " << counter << endl; }
virtual ~Data()
{
counter -= 1;
cout << "calling destructor " << counter << endl;
}
bool operator<(const Data & right) const {
return _x < right._x && _y < right._y;
}
private:
int _x;
int _y;
};
This will show the copy constructor being called too.
The other two destructor calls are destroying temporary objects that were initially copy-constructed. Add an explicit copy constructor to the object, and you'll see it getting invoked.
To figure out why the copy-constructor get called, observe that the parameter to std::map::insert is a std::pair. Now consider, for a moment, what must actually happen in order for this sequence of events to take place to actually occur: a std::pair getting constructed, containing your object; and for this std::pair to get inserted into the actual map.
For an additional level of insight and understanding, use a debugger to set a breakpoint in your copy-constructor, and examine the stack trace each time the breakpoint gets hit.

Expression _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error

After adding parameter by reference "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)" debug assertion failed.
class Stack
{
private:
const std::uint32_t m_maxElement;
protected:
std::uint32_t m_currentElement;
int *m_tab;
public:
Stack(std::uint32_t p_maxElement);
virtual ~Stack();
void push(int p_element);
std::int32_t pop(void);
std::uint32_t size(void) const;
};
Stack::Stack(std::uint32_t p_maxElement) : m_maxElement(p_maxElement), m_tab(new int[m_maxElement]), m_currentElement(0u)
{}
Stack::~Stack()
{
if (m_tab) delete[] m_tab;
}
void Stack::push(int p_element)
{
if (m_currentElement < m_maxElement)
{
m_tab[m_currentElement] = p_element;
++m_currentElement;
}
}
std::int32_t Stack::pop()
{
if (m_currentElement > 0u)
{
return m_tab[--m_currentElement];
}
}
std::uint32_t Stack::size() const
{
return m_currentElement;
}
/*************************************************************************/
std::int32_t median(Stack p_stack)
{
std::vector<std::int32_t> l_container(p_stack.size());
while (p_stack.size())
{
l_container.push_back(p_stack.pop());
}
std::sort(l_container.begin(), l_container.end());
int l_containerSize = l_container.size();
int l_middleIndex = l_containerSize / 2;
if (l_containerSize % 2 == 0)
{
int l_firstMiddleElement = l_container[l_middleIndex - 1];
int l_secondMiddleElement = l_container[l_middleIndex];
return (l_firstMiddleElement + l_secondMiddleElement) / 2;
}
else
{
return l_container[l_middleIndex];
}
return 0;
}
std::int32_t arithmeticAverage(Stack p_stack)
{
std::int32_t l_sum = 0;
int l_stackSize = p_stack.size();
while (p_stack.size())
{
l_sum = p_stack.pop();
}
return l_sum / l_stackSize;
}
int main()
{
Stack firstStack(10);
firstStack.push(2);
firstStack.push(4);
firstStack.push(8);
std::cout << "firstStack.pop() = " << firstStack.pop() << std::endl;
std::cout << "median(firstStack) = " << median(firstStack) << std::endl
std::cout << "arithmeticAverage(firstStack) = " << arithmeticAverage(firstStack) << std::endl;
return 0;
}
In case of
std::int32_t median(Stack &p_stack)
is ok. Instead of
std::int32_t median(Stack p_stack)
After that line "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)" appears.
If your median function takes Stack by value the compiler has to make a copy of the original Stack. Because you have not defined a copy constructor in Stack the compiler generated its own which does member wise copy which means it just copies the value of the pointer over so that two instances of Stack now point at the same bit of memory. Then when the median function finishes execution the destructor of the copy is called and deletes the memory therefore now the original Stack in your main is pointing at a block that has been freed which causes the error.
When median takes a reference there is no copy being made - it gets a reference to the original Stack in main and no destructor gets called.
I suggest you change your code so that median and the other function take a const reference to Stack as their parameters.

Is this code legal in ISO C++?

So I'm trying to implement function parameters which can be uninitialized. Here is the code which I have written. My question is if it's legal by the ISO C++ standard (version 14 if possible).
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename type>
struct nzeroinittmpliteral
{
nzeroinittmpliteral() { }
nzeroinittmpliteral(type arg) { d = arg; }
//nzeroinittmpliteral(const nzeroinittmpliteral &) = delete;
operator type () & { return d; }
operator type () && { return d; }
type d;
} ;
void func(bool bIsPointerValid, nzeroinittmpliteral<int *> pVar = {})
{
if(bIsPointerValid)
{
cout << *pVar << endl;
}
else
{
pVar = new int;
*pVar = 8;
cout << *pVar << endl;
delete pVar;
}
}
int main()
{
func(true, { (int *)&(const int &)int{9} } );
func(false);
}
If you want to pass a parameter that may be uninitialized, simply don't pass it, use overloading. Look:
void func(int value)
{
cout << value << endl;
}
void func()
{
// no 'value' was initialized here :)
func(8);
}
Or simply give a default value to the parameter if you will provide one anyway in your body:
void func(int value = 8)
{
cout << value << endl;
}
Besides that, you can take a look at boost::optional:
void func(boost::optional<int> optvalue = boost::none) {
if (optvalue) {
cout << *optvalue << endl;
} else {
// nothing passed
cout << "foo" << endl;
}
}
Directly answering your question: your code is valid.
func(true, { (int *)&(const int &)int{9} } );
By casting the temporary to a const reference, you extend its lifetime to the lifetime of the reference itself, which ends after func returns. But this is too redundant, you could simply have written:
void func(int* value) { if (value) {...} }
func(&(const int &)9);
func(nullptr);
The actual parameter being passed is your nzeroinittmpliteral and it is initialized by calling one of the constructors, always. The default constructor doesn't initialize the d member, but this is no big improvement as it is just a pointer. Using nullptr is better and removes the need for the bool parameter.