C++ assign dereference pointer object to a variable and use that - c++

Hea everyone!
First of all, I am a completely new to C++ coming from a basic C background so it might be a little weird why I ask this.
The use scenario is that I want to change a map inside a different function by passing the map as a pointer to that function. Because I was reusing someone else's code, it was easier to assign the dereference to a variable instead of changing all of the references. This results in a similar case as this:
using namespace std;
typedef map<long, double> tl_t;
void fillmap(tl_t* m_p) {
tl_t m = *m_p;
m.insert(pair<long, double>(4, 3.0));
}
int main(int argc, char** argv) {
tl_t m;
cout << "Size: " << m.size() << "\n";
fillmap(&m);
cout << "Size: " << m.size() << "\n";
return 0;
}
The funny thing is that now both Size: strings return 0 and the original map m in the main function does not seem to be changed. This, however, works:
using namespace std;
typedef map<long, double> tl_t;
void fillmap(tl_t* m) {
(*m).insert(pair<long, double>(4, 3.0));
}
int main(int argc, char** argv) {
tl_t m;
cout << "Size: " << m.size() << "\n";
fillmap(&m);
cout << "Size: " << m.size() << "\n";
return 0;
}
As far as I can tell, these 2 cases should be working the same as both the reference of m in the main and fillmap function reference the same object. Of course the two m variables reside somewhere differently but should be referencing the same object.
As I am writing this, one thing that might be the problem is that variable m in main IS the map object while the variable m in fillmap TRIES to be the map object but can't because dereferencing the m_p pointer and assigning it to that last m doesn't actually make the last m a reference to the same object but actually copies it. Am I on the right track here?
And yes, I do know in normal use cases you should use a parameter reference in a similar situation, but this bugged the hell out of me :P.
Hopefully someone can enlighten me!

In C++ you have to add & to explicitly say that variable is reference.
In your example:
tl_t& m = *m_p;
should help.
If you use just "tl_t" you create local copy of the object which is destroyed once you leave fillmap function.
Example:
struct X {
int a,b;
}
Now types:
X - place in memory containing both a and b value.
X& - place in memory containing reference (const pointer) to the X.
X* - place in memory containing pointer to the X.
In both X and X& you can access fields of class using dot (xobject.a, xobject.b) but these are not same types.

It is because that
tl_t m = *m_p;
m will be construct by call the copy constructor, the copy process is by value. You just insert the pair<long, double>(4, 3.0) into m, not m_p
However,
(*m).insert(pair<long, double>(4, 3.0))
*m is the object you passed in by pointer, so, the pair<long, double>(4, 3.0) is inserted to *m itself.

Related

Understanding std::pair <const T&, const U&>

I am trying to create a class that instantiates an std::pair<const T&, const U&> from two member variables. I started this out of curiosity and was surprised to see the results from creating multiple objects of, in the example below, Pair.
struct Pair {
int num;
string s;
pair<const int&, const string&> pr{make_pair(num, s)};
Pair(int n, const string& s) : num(n), s(s) {}
};
ostream& operator<<(ostream& out, const Pair& p) {
out << setw(2) << p.num << ", " << p.s << ": <" << p.pr.first << "," << p.pr.second << ">";
return out;
}
/******************************************************************************/
int main() {
cout << string(15, '-') << " PIECEMEAL " << string(15, '-') << endl;
Pair p1{1, "normal1"};
Pair p2{2, "normal2"};
cout << p1 << endl;
cout << p2 << endl << endl;
cout << string(15, '-') << " VECTOR " << string(15, '-') << endl;
vector<Pair> v;
for (int i=0; i< 05; ++i) {
v.emplace_back(i, "from_vec'" + ::to_string(i) + "'");
}
for(const auto & p : v) {
cout << p << endl;
}
}
I thought that the const reference type declarations within the pair would refer to the Pair members, num and s, respectively. However, when I create multiple Pairs, it appears that the references within the pair end up referencing (to some degree) the Pair members of the most recently constructed Pair.
Here is the output:
--------------- PIECEMEAL ---------------
1, normal1: <2,normal2>
2, normal2: <1586964272,normal2>
--------------- VECTOR ---------------
0, from_vec'0': <4,from_vec'4'>
1, from_vec'1': <1586964272,from_vec'4'>
2, from_vec'2': <1586964272,from_vec'4'>
3, from_vec'3': <1586964272,from_vec'4'>
4, from_vec'4': <1586964272,from_vec'4'>
I looked at cppreference in an attempt to understand what was going on, but still not grasping it.
Why do the references within the pair no longer reference the Pair members, num and s?
There are 2 problems with your code.
First:
pair<const int&, const string&> pr{make_pair(num, s)}
std::make_pair(num, s) first create a temporary pair<int, string>. Then pr will be initialized with this temporary pair.
Note that pair<int, string> is not the same as pari<const int&, const string&>, which means it will not trigger the default move constructor.
Instead, if you looked at cppreference, this would trigger the 6th overload, and essentially assign pr.first and pr.second with this temporary pair, hence dangling reference.
To fix it, you should specifically create a pair of references with:
pr{std::make_pair(std::ref(num), std::ref(s)}
Or just create pr directly with num and s:
pr{num, s}
Second:
v.emplace_back(i, "from_vec'" + ::to_string(i) + "'");
This line would trigger the default move constructor, since you didn't specify one yourself, which would perform a member-wise move on Pair.
However, what happens when you move pr to the new Pair? The old pr was referencing the old num and old s. Moving the old pr to the new Pair doesn't change the value of pr, hence it will continue referencing the old num and old s, hence dangling reference.
So instead of relying on default generated move constructors, you must define them manually:
Pair(Pair&& pair) noexcept
: num(std::exchange(pair.num, {})
, s(std::move(pair.s))
{}
Note, you don't need to construct pr within initializer list since you already have a default initializer for pr.
Demo
You are inadvertently creating a pair that holds const references to another pair that was allocated on the stack and immediately freed. In other words, undefined behavior.
Step by step, here's what's happening when you instantiate a Pair:
The Pair constructor is called.
The Pair initializer is called.
The initializer calls make_pair, creating a pair of int and std::string on the stack.
This temporary pair gets assigned to pr, and the const references inside it now refer to the memory of the temporary pair.
The initializer exits, freeing the temporary pair on the stack. the int and string references inside pr now refer to memory that has been freed.
What's more, you really shouldn't be storing references to other members inside your struct, for memory safety reasons. If you want a std::pair of your two values, you should make a member function that returns it instead of storing it inside the struct itself.

Is it Safe to Assign vector With operation= vector() in C++

Is it safe to assign vector later after initialization.
Let say i have a global vector variable. But i don't want to initialize the value at the beginning.
#include <iostream>
#include <vector>
using namespace std;
vector<int> globalVector;
int myNumber=123;
void setVector()
{
// Is it safe to set the vector as shown below ?
globalVector = vector<int>{1,2,3,4};
}
int main(int, char**) {
setVector();
for (int x=0; x<globalVector.size();x++)
{
cout << "Val = " << globalVector[x] << endl;
}
std::cout << "Hello, world! : " << myNumber << endl;
return 0;
}
on VSCode i can see some information said :
std::vector<int> &std::vector<int>::operator=(std::vector<int> &&__x)
+2 overloads
%Vector move assignment operator.
Parameters:
__x – A %vector of identical element and allocator types. The contents of __x are moved into this %vector (without copying, if the allocators permit it). Afterwards __x is a valid, but unspecified %vector. Whether the allocator is moved depends on the allocator traits.
The description said "move without copying". will the globalVector corrupt when the program exit from function setVector ?
Yes that is safe, although
The notation globalVector = {1,2,3,4}; is clearer.
It's not thread-safe.
Use globalVector.at(x) rather than globalVector[x] unless performance really matters, as the behaviour of the latter can be undefined for some values of x. In this particular case, a range-for loop would be better still: for (auto&& i: globalVector).
The description said "move without copying". will the globalVector corrupt when the program exit from function setVector ?
It means that operator= moved content of new vector without copy operation. The vector used for initialization is invalid after that operation. However it doesn't impact you since it is the object used only for initialization so is destroyed just after that.
Yes, it is totally safe, but I recommend you not to use global vector
instead write
int main() {
std::vector<int> globalVector = vector<int>{1,2,3,4};
for (int i=0; i<globalVector.size();i++) {
cout << "Val = " << globalVector.at(i) << '\n';
}
std::cout << "Hello, world! : " << myNumber << '\n';
return 0;
}

Why can't functions change vectors when they can change arrays?

I am trying to move from arrays to vectors in cpp for problem-solving and its overall benefits. I am facing some issues here even though this logic works on arrays.
#include <iostream>
#include <vector>
using namespace std;
void PrintArray(vector<int> v) { // O(n)
for (int i=0; i<v.size(); i++)
cout << v[i] << " ";
cout << endl;
}
void LF1(vector<int> A) { // O(n)
int temp = A[0],i;
for (i=0; i<A.size()-1; i++)
A.at(i) = A.at(i+1);
A.at(i)=temp;
// PrintArray(A); <-- shows updated array here
}
void LF(vector<int> A, int d) {
d = d % (A.size());
cout << "d%n: " << d << endl;
for (int j=0; j<d; j++)
LF1(A);
PrintArray(A);
}
int main(int argc, char const *argv[]) {
vector<int> A;
int d;
for(int i=1; i<6; i++)
A.push_back(i);
PrintArray(A);
cout << "Enter number of Left rotations to perform : ";
cin >> d;
LF(A,d);
return 0;
}
Problem 1: When I am calling LF1 inside of LF it returns the same array without rotating but when I write the code for LF1 inside of LF it seems to rotate.
Problem 2: The PrintArray() prints the rotated array only when called from LF1() or just immediately after its code when written (instead of calling LF1()) in LF() when causes it to print the array d times. Where d is the required rotations.
Regarding what you're doing wrong...you are passing the vectors by value. You don't expect changes to an integer to affect it in the caller when you pass it as a value...
void SomeFunction(int i) {
i = i + 1;
printf("Inside SomeFunction %d\n", i); // changed, 11
}
int i = 10;
SomeFunction(i);
printf("Outside SomeFunction %d\n", i); // unchanged, 10
...if you wanted to see a change, you would have to pass a pointer, such as int *pi, and then update it as *pi = *pi + 1;
The same principle applies to vectors and other C++ classes. If you just pass it as a value, the whole vector is copied. (Well, if it needs to be, a temporary could just be reused). But for now think of it as being copied: just as there's a difference between passing an integer and a pointer-to-an-integer, there's a difference between a vector and a pointer-to-a-vector.
You could pass a pointer to the vector if you intend to change it...or... C++ offers another tool called the reference, where references are very much like pointers but with a few differences. If you just changed your arguments to vector<int> &A then your code should work, because the arrays would be "passed by reference" instead of getting copied when they are "passed by value", so changes would take effect. If you don't want a function to need to be able to modify an array but still want to avoid the copy, pass by const reference, e.g. const vector<int> &A (e.g. this is what your PrintArray() should use).
You might not want to get too hung up on the details of references for now, other than thinking of it as a "convenient kind of pointer where you don't have to put the * on all the places you want to dereference". But in case you want to know more specifics:
What are the differences between a pointer variable and a reference variable in C++?
I am facing some issues here even though this logic works on arrays.
And this is probably the source of your confusion. Which comes from the fact that C-style arrays decay into pointers under the hood:
Passing an Array by reference in C
I think that's something that it's reasonable to be confused by, given that other types (such as integers and vectors) don't. It's just a quirk of C, that C++ inherited. So when C++11 wanted to clean that up, a wrapper class called std::array was introduced:
https://embeddedartistry.com/blog/2017/6/28/an-introduction-to-stdarray
https://en.cppreference.com/w/cpp/container/array
But C++ also has an algorithm to do rotation...
So if you want to see a good example of how this would be done, it's a place to start:
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> v{1, 2, 3, 4};
std::rotate(v.begin(), v.begin() + 1, v.end());
for (auto &i : v)
std::cout << i << " ";
std::cout << "\n";
}
That will get you 2 3 4 1. The documentation has other examples, read through:
https://en.cppreference.com/w/cpp/algorithm/rotate

Retrieval of value back from C++ map<T, const T&> returns same object

I created a map of type map<T, const T&>. For current example purpose, let say T is:
class Bar {
public:
Bar(int x) {this->x = x;}
int x;
};
Next I create a map and insert Bar keyed with some integers.
Bar bs[] = {Bar(1), Bar(2), Bar(3)};
map<int, const Bar&> my_map;
for (int i = 0; i < 3; i++) {
const Bar &b = bs[i];
cout << "Setting map." << i
<< " with x = " << b.x << endl ;
my_map.insert(std::make_pair(i, b));
}
So far everything looks good, and b.x prints the values 1; 2; 3 as expected. Next we retrieve these values back.
for (int i = 0; i < 3; i++) {
auto iter = my_map.find(i);
if (iter == my_map.end()) {
cout << "Not found!" << endl;
continue;
}
cout << "map." << i << " = " << iter->second.x << endl;
}
The output prints the last value each time as shown below.
// map.0 = 3
// map.1 = 3
// map.2 = 3
And that's what is confusing to me, as I expect 1; 2; 3. If I replace value type of map with just const Bar it gives 1; 2; 3. I've been trying to make sense out of it, but so far it just looks like undefined behaviour to me. The wildest explanation I can imagine is that &b is like a box storing pointer to the object, and the box ends up being shared across loop, and make_pair uses &b as a box value than like a pointer/reference (and hence explains the last value being printed).
Edit: I understand it may not be good idea to use map like this, but I'm curious why this is happening than what should I be using instead. As in semantically, what did I miss when I wrote this and why it went through compiler, or why compiler made whatever assumption it made.
Edit: Example on repl.it running the code: https://repl.it/repls/IgnorantExhaustedBluejay
Essentially the same problem as here: How can I have a pair with reference inside vector?
Your call to std::make_pair creates a temporary std::pair object that does not have a reference as its second member. The second member of the pair is a regular value of type Bar. Meanwhile, your map stores references. The reference gets bound to the second member of the temporary created by std::make_pair. Later the temporary gets destroyed. The reference becomes dangling.
Each temporary on each iteration of the cycle is apparently created at the same location in memory. So, all these dangling references in your map refer to the same location in memory. Which just happens to hold the residual value of 3 at the time of printing. That explains the output.
A map with raw references is not a very good idea. But if you want to somehow force it to work with raw references, stop using std::make_pair. Instead, manually construct a proper std::pair, making sure to explicitly specify the proper types
my_map.insert(std::pair<const int, const Bar &b>(i, b));
Or you can keep using std::make_pair as follows
my_map.insert(std::make_pair(i, std::cref(b)));
But switching entirely to std::reference_wrapper and std::cref is a better idea.
P.S. BTW, in C++17 mode GCC refuses to compile the code with raw references. C++14 mode does compile it.
I wasn't even aware that it's possible to have a map of references
You should probably simply store the object you want directly :
map<int, Bar> my_map;
If you want the "Bar"s objects to live outside the map, you should use pointers instead of references. Just be sure you don't destruct the Bar objects without removing them from the map :
map<int, Bar*> my_map;
my_map[2] = &bs[0];
and then:
int x = my_map[2]->x;
Edit
I think the map is holding a reference to the temporary pair. You can see this in debug if you extract the creation of the pair :
auto tempPair = std::make_pair(i, b);
my_map.insert(tempPair);
Then after adding bs[0] if we run the creation of the pair, the value of my_map[0] change even before adding the second one:
This makes it work:
my_map.insert(std::make_pair(i, std::reference_wrapper<const Bar>(b)));

is there a cleaner way to right operator[]() for a vector? [duplicate]

If I define a pointer to an object that defines the [] operator, is there a direct way to access this operator from a pointer?
For example, in the following code I can directly access Vec's member functions (such as empty()) by using the pointer's -> operator, but if I want to access the [] operator I need to first get a reference to the object and then call the operator.
#include <vector>
int main(int argc, char *argv[])
{
std::vector<int> Vec(1,1);
std::vector<int>* VecPtr = &Vec;
if(!VecPtr->empty()) // this is fine
return (*VecPtr)[0]; // is there some sort of ->[] operator I could use?
return 0;
}
I might very well be wrong, but it looks like doing (*VecPtr).empty() is less efficient than doing VecPtr->empty(). Which is why I was looking for an alternative to (*VecPtr)[].
You could do any of the following:
#include <vector>
int main () {
std::vector<int> v(1,1);
std::vector<int>* p = &v;
p->operator[](0);
(*p)[0];
p[0][0];
}
By the way, in the particular case of std::vector, you might also choose: p->at(0), even though it has a slightly different meaning.
return VecPtr->operator[](0);
...will do the trick. But really, the (*VecPtr)[0] form looks nicer, doesn't it?
(*VecPtr)[0] is perfectly OK, but you can use the at function if you want:
VecPtr->at(0);
Keep in mind that this (unlike operator[]) will throw an std::out_of_range exception if the index is not in range.
There's another way, you can use a reference to the object:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {7};
vector<int> *p = &v;
// Reference to the vector
vector<int> &r = *p;
cout << (*p)[0] << '\n'; // Prints 7
cout << r[0] << '\n'; // Prints 7
return 0;
}
This way, r is the same as v and you can substitute all occurrences of (*p) by r.
Caveat: This will only work if you won't modify the pointer (i.e. change which object it points to).
Consider the following:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {7};
vector<int> *p = &v;
// Reference to the vector
vector<int> &r = *p;
cout << (*p)[0] << '\n'; // Prints 7
cout << r[0] << '\n'; // Prints 7
// Caveat: When you change p, r is still the old *p (i.e. v)
vector<int> u = {3};
p = &u; // Doesn't change who r references
//r = u; // Wrong, see below why
cout << (*p)[0] << '\n'; // Prints 3
cout << r[0] << '\n'; // Prints 7
return 0;
}
r = u; is wrong because you can't change references:
This will modify the vector referenced by r (v)
instead of referencing another vector (u).
So, again, this only works if the pointer won't change while still using the reference.
The examples need C++11 only because of vector<int> ... = {...};
You can use it as VecPrt->operator [] ( 0 ), but I'm not sure you'll find it less obscure.
It is worth noting that in C++11 std::vector has a member function 'data' that returns a pointer to the underlying array (both const and non-const versions), allowing you to write the following:
VecPtr->data()[0];
This might be an alternative to
VecPtr->at(0);
which incurs a small runtime overhead, but more importantly it's use implies you aren't checking the index for validity before calling it, which is not true in your particular example.
See std::vector::data for more details.
People are advising you to use ->at(0) because of range checking. But here is my advise (with other point of view):
NEVER use ->at(0)! It is really slower. Would you sacrifice performance just because you are lazy enough to not check range by yourself? If so, you should not be programming in C++.
I think (*VecPtr)[0] is ok.