I'm sure this is very simple, but I'm rather new to smart pointers, and I couldn't find an answer to this.
Scenario is very simple:
I have a class A, that holds a shared_ptr to some object X:
class A{
shared_ptr<const X> _asX;
}
now after a series of function calls, I'm creating a new object of type B, that also holds this X. something like:
class B {
private:
shared_ptr<const X> _bsX;
public:
B(): _bsX(nullptr) // - maybe this is problematic {}
foo(shared_ptr<const X>& x)
{
_bsX = x;
// The line above gives me undefined behavior,
// and when I run valgrind I get "Conditional jump or move
// depends on uninitialized value(s)",
// telling me this is not the correct way to do things.
}
Note that it is deliberate the foo really sets the value of _bsX and not the constructor.
So as stated above - depending on the compiler, I something get segmentation faults - which usually means some value was not initialized, and later confirmed by valgrind.
So what should I do - I've tried using 'reset' etc. but I got so confused I'm asking for your help.
Could it be the const ? or the pass by reference ? or the '=' operator.
And while we're at it - should I be passing X with its wrapper (the shared_ptr) to foo, or should I pass the raw pointer, and then make it shared ? if so - could you please give an example. I tried that as well, and got errors.
Ok, I found the problem, and it's no related to smart pointers at all, but since I'm new to this - I thought it might be.
I'll leave this answer for future references. This is what I did (simplified):
class A{
private:
shared_ptr<const int> _num;
public:
A()
{
_num = make_shared<const int>(5);
}
const shared_ptr<const int>& getNum() const {return _num; }
void printNum()
{
cout << *_num.get() << endl;
}
};
class B
{
public:
struct C{
C() : _num(nullptr){}
void boo(shared_ptr<const int> & num) { _num = num;}
shared_ptr<const int> _num;
};
B() {}
void foo(shared_ptr<const int>& num)
{
cs.reserve(2);
for (uint32_t i = 0; i < 2 ; ++i) {
cs.push_back(C()); // This was missing.
cs[i].boo(num);
}
}
void printCNum()
{
for (C c : cs) {
cout << *c._num.get() << endl;
}
}
private:
vector<C> cs;
};
int main()
{
A a{};
shared_ptr<const int> xx = a.getNum();
B b{};
b.foo(xx);
a.printNum();
b.printCNum();
}
Silly me, I thought that when you reserve a vector of Objects (not pointers/references) it also calls their constructor. It turn out it's not. Specifically, I increased the capacity of the vector, but not its size.
Related
I would like to declare an alternative way to access a class member (an array position specifically), as in
class Foo {
int a[2];
int &a_first = a[0];
};
such that any access to a_first in a Foo instance is for all purposes equivalent to accessing a[0] of that same instance.
The code above works as I expected with singular instances and single vectors of the class, but when used on a nested vector the reference address differs from the member address:
#include <iostream>
#include <vector>
class A {
public:
int m;
int &mref = m;
};
int main()
{
A a;
std::cout << (&a.m == &a.mref) << '\n'; // output: 1
std::vector<A> av1(1);
std::cout << (&av1[0].m == &av1[0].mref) << '\n'; // output: 1
std::vector<std::vector<A>> av2(1, std::vector<A>(1));
std::cout << (&av2[0][0].m == &av2[0][0].mref) << '\n'; // output: 0
return 0;
}
I thought reference variables acted as aliases of their assigned variable and were resolved at compile time without being assigned any actual memory at runtime, unlike pointers. Why is this not consistent with the behavior displayed above? What would be a correct way to achieve the alias I want?
The code above works as I expected
Actually it doesn't:
class A {
public:
int m{};
int &mref = m;
};
int main()
{
A a;
A a2 = a;
std::cout << (&a2.m == &a2.mref) << '\n'; // output: 0
};
A reference can be bound only on initialization. Copying will copy the value, not re-bind the reference. So any copy of an object of type A will mess up your reference. This is what happens in your nested vector example. You don't need a nested vector to see this. Try and push in a vector<A>, the vector will have to resize and during the resize will copy its elements, messing your reference.
I thought reference variables acted as aliases of their assigned variable ...
True
... and were resolved at compile time without being assigned any actual memory at runtime, unlike pointers.
Not always. You cannot always resolve at compile time the reference, in which case the reference will actually be implemented with a pointer behind the scenes.
Possible solutions:
use std::reference_wrapper, the copy assignment operator rebinds the reference, but you will need to implement custom copy constructor/assignments for your class:
class A {
public:
int m{};
std::reference_wrapper<int> mref = m;
A() = default;
A(const A& other) noexcept
: m{other.m},
mref{m}
{}
A& operator=(const A& other) noexcept
{
m = other.m;
mref = m;
return *this;
}
};
use a method that returns a reference to the variable
class A {
public:
int m{};
int& mref() { return m; }
const int& mref() const { return m; }
};
Class A
{
public:
A();
A(int x , int y);
Private:
int x;
int y;
}
Class B
{
public:
B();
A getApointerobject() const;
Private:
A *APointerObject;
int main()
{
B bObj;
cout << bObj.getApointerobject(); //i overloaded the << so that i can //output B objects but it crushes
}
//Class B implementation (This is where i struggle)
A getApointerobject() const {
return *getApointerobject;
}
In B::getApointerobject() you call it recursively. You should change to
A getApointerobject() const {
return *APointerObject;
}
Is B::APointerObject initialized before you call getApointerobject() method?
In getApointerobject you are trying to return the address of the method getApointerobject itself. I guess you code is not even compiling right now?
I guess you want to return your APointerObject
A B::getApointerobject() const {
return *this->APointerObject;
}
But be advised: Built in types, including simple pointers don't have a default constructor. So, since you don't initialise APointerObject in class Bs constructor, you would use a wild pointer. Which means you program would crash at runtime or worse (undefined behavior)
class A{
private:
int a;
public:
const int &ref = a;
};
int main() {
A obj;
obj.a = 20; // error cause private
obj.ref = 30; // not private but const so ERROR
return 0;
}
I'm trying to make a member variable accessible but read only through the interface. Currently I've tried this approach and it seems to compile fine. I made a const reference to my original variable int a and made it public. Is there anything that's wrong with this practice that I might be missing out? Or is this example safe and sound to use for practical purposes?
Nothing wrong with providing a member function with const correctness applied (and I've used that too and intend to do so always), but I'm asking is there any thing wrong with this way if I have to provide a variable that is only read-only.
Thankyou :)
class A{
private:
int a;
public:
const int &ref = a;
};
is there any thing wrong with this way if I have to provide a variable that is only read-only
There are at least a couple drawbacks with this design decision for class A.
1: Class Size
Also as Dieter Lücking mentions in a
comment:
increasing the size of the class, needlessly
2: Copy Semantics
It breaks the compiler generated copy assignment operator. For example, the following code behavior is generally desirable but doesn't work.
A obj1;
// ...
A obj2;
// make changes to 'obj2'
// Update 'obj1' with the changes from 'obj2'
obj1 = obj2; // This copy doesn't work!
More information:
Should I prefer pointers or references in member data?
Assignment operator with reference class member
Thinking in C++, 2nd ed. Volume 1 ©2000 by Bruce Eckel, 11: References & the Copy-Constructor
There are certain rules when using references:
A reference must be initialized when it is created. (Pointers can be initialized at any time.)
Once a reference is initialized to an object, it cannot be changed to refer to another object. (Pointers can be pointed to another object at any time.)
You cannot have NULL references. You must always be able to assume that a reference is connected to a legitimate piece of storage.
It may be possible to implement a custom assignment operator but that's more code to maintain (i.e., another drawback in my opinion).
#include <iostream>
class A
{
private:
int a;
public:
explicit A(int value) : a(value) {}
A& operator=(const A& other)
{
a = other.a;
return *this;
}
const int& ref = a;
};
int main()
{
A obj1(10);
std::cout << "1: " << obj1.ref << "\n";
A obj2(20);
std::cout << "2: " << obj2.ref << "\n";
obj1 = obj2;
std::cout << "1: " << obj1.ref << "\n";
return 0;
}
The idiomatic way to address this issue is to use a proper accessor function.
class A {
private:
int a;
public:
int getA() const { return a; }
};
The standard way to do this in C++ is by making the actual member private but including a public 'getter' method for the interface, as below:
class A{
private:
int a;
public:
int get_a() const { return a; }
A() : a(20) {}
};
int main() {
A obj;
int n = obj.get_a(); // n = 20
return 0;
}
The user cannot set the value of A::a but can use A::get_a to retrieve its value.
Suppose I have a class A, whose constructor requires an argument x.
class A
{
public:
int a;
A(int x) { a = x; std::cout << a << std::endl; }
~A() {}
};
Now I want to allocate an array of A, and wrap it in another class B (in reality it should be a 2-dimensional array of A, mapped onto a 1-dimensional array, which is why I need to wrap it). Since constructor of A requires argument, I cannot use new[] (…right?), so I have to have an A**. Also I don’t want B to know about x, so my B is like this:
class B
{
private:
A** As;
const int n;
public:
B(int nn): n(nn) { As = new A*[n]; }
~B() { delete[] As; }
A* at(int i) { return As[i]; }
const A* at(int i) const { return As[i]; }
};
Note that “subscription operator” loosely means that at() function. Now my main function is like this:
int main()
{
B b(3);
int x = -1;
for(int i = 0; i < 3; i++)
{
b.at(i) = new A(x);
}
return 0;
}
When I compile this with g++, it prints an error “lvalue required as left operand of assignment” at my “new” line. Then I change my signature of at() to
A*& at(int i)
and it works.
What’s bothering my is that A*&, which just looks weird to me…
Is this A*& something I should use? Or any other way to deal with an array of objects, whose constructor requires arguments? BTW we don’t have c++11 and boost available on our target machine…
"Or any other way to deal with an array of objects, whose constructor requires arguments?"
Use std::vector, you don't need C++11 for it, neither any additional libraries:
#include <vector>
...
std::vector<A> myObjects(n, A(0)); // objects will be constructed by calling A(0)
Your class B could look the following way:
class B
{
private:
std::vector<A> As;
const int n;
public:
B(int n): n(n), As(std::vector<A>(n, A(0))) { }
// no explicit destructor needed
// memory management is handled by std::vector object automatically
A& at(int i) { return As[i]; }
const A& at(int i) const { return As[i]; }
};
Note that vector's elements are stored within continuous block of memory and lifetime of these elements is tied to the lifetime of instance of B. Once the B is destructed, so is the vector and so are the elements that were stored in it. If n is a constant known at compile time, you might also consider using std::array instead.
The & operator has a role to change an function parameter or a return variable to a reference.
Without & the value of the variable will be copied into a temporal variable, therefore the original variable will not be sensible to any value changes.
By referenced handling the parameter will be the original variable only the name differs, but signs the same memory block.
In this example the b.at(i) statement will be copied into a temporary constant variable, which is unusable in the left side of = statement.
But by referenced return of this statement it points to the original As[i] memory block, only the 'name' differs, and so can be changed its value too.
I don't think is a duplicate question. There are similar ones but they're not helping me solve my problem.
According to this, the following is valid in C++:
class c {
public:
int& i;
};
However, when I do this, I get the following error:
error: uninitialized reference member 'c::i'
How can I initialise successfully do i=0on construction?
Many thanks.
There is no such thing as an "empty reference". You have to provide a reference at object initialization. Put it in the constructor's base initializer list:
class c
{
public:
c(int & a) : i(a) { }
int & i;
};
An alternative would be i(*new int), but that'd be terrible.
Edit: To maybe answer your question, you probably just want i to be a member object, not a reference, so just say int i;, and write the constructor either as c() : i(0) {} or as c(int a = 0) : i(a) { }.
A reference must be initialised to
refer to something.
int a;
class c {
public:
int& i;
c() : i (a) {};
};
Apart from the sweet syntax, a key feature of references is that you are pretty sure that it always point to a value (No NULL value).
When designing an API, it forces user to not send you NULL.
When consuming an API, you know without reading the doc that NULL is not an option here.
References have to be initialized upon creation. Thus you have to initialize it when the class is created. Also you have to provide some legal object to reference.
You have to use the initializer in your constructor:
class c {
public:
c(const int& other) : i(other) {}
int& i;
};
Reference should be initialised either by passing data to constructor or allocate memory from heap if you want to initialize in default constructor.
class Test
{
private:
int& val;
std::set<int>& _set;
public:
Test() : val (*(new int())),
_set(*(new std::set<int>())) { }
Test(int &a, std::set<int>& sett) : val(a), _set(sett) { }
};
int main()
{
cout << "Hello World!" << endl;
Test obj;
int a; std::set<int> sett;
Test obj1(a, sett);
return 0;
}
Thanks
template<class T>
class AVLNode {
private:
T & data;
public:
AVLNode(T & newData) {
data = newData;
}
};