I am trying to dereference a referenced vector address as follows:
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> p;
p.push_back(1);
p.push_back(2);
p.push_back(3);
p.push_back(4);
p.push_back(5);
p.push_back(6);
cout << (*(&p)) << endl;
cout << (*(&p + 3)) << endl;
return 0;
}
But it fails.
Expecting output:
1
4
std::vector<int> p; is an object that manages consecutive storage of elements of type int.
&p would be an address of such an object. What that object contains is unspecified. You can expect a vector object to contain, e.g. the pointer to an array of elements allocated on the heap, the current size and capacity.
To get a pointer to the underlying elements, use p.data().
To access a specific element of a vector can use the overloaded operator[] (e.g. p[0], p[3]).
An iterator (e.g. p.begin()) can also be used as an abstraction around a pointer to an element:
int main() {
vector<int> p;
p.push_back(1);
p.push_back(2);
p.push_back(3);
p.push_back(4);
p.push_back(5);
p.push_back(6);
cout << (*(p.begin())) << endl;
cout << (*(p.begin() + 3)) << endl;
}
The benefit of using iterators in place of raw pointers is that the access is bounds-checked in debug builds (in VC++ at least), and it will seamlessly work with other types of sequential containers.
Related
I have this code I don't understand why I need to delete and then pop_back().
Can I do it in 1 operation only ?
struct T
{
T(int n):x(n){};
int print() {
return x;
};
private:
int x;
};
int main(int argv,char** argc)
{
std::vector t = { new T(1),new T(2)};
delete t.back();
std::cout << t.size() << std::endl;
std::cout << t.back()->print() << std::endl;
t.pop_back();
std::cout << t.size() << std::endl;
std::cout << t.back()->print() << std::endl;
return 0;
}
The output - as you can see after delete it looks like the vector is still holding the element witout the object:
2
179185600
1
1
My question is why do I need delete and then remove , can't same operation be done in single command ?
1. The issues in your code:
This line:
delete t.back();
Is not removing any element from the std::vector. Your std::vector is holding pointers, and it will continue to hold the same pointers.
What the line above does is deallocate the object pointed by the element in the std::vector.
This line (the 1st occurance):
std::cout << t.back()->print() << std::endl;
Invokes UB (Undefined Behavior) because you derefernce a pointer after it has beed deleteed.
Then after:
t.pop_back();
The last pointer (the one that you deleteed, i.e. freed) is removed from the std::vector, and t.back() is the other pointer you inserted, which is still valid.
2. A different approach - avoid pointers:
Having wrote all that, in this case you do not actually need to deal with pointers at all.
You can use std::vector<T>, (instead of T* like you did) and store the elements by value. You will not need to new or delete anything.
Code example:
#include <vector>
#include <iostream>
struct T
{
T(int n) :x(n) {};
int print() { return x; };
private:
int x;
};
int main(int argv, char** argc)
{
std::vector t = { T{1}, T{2} };
std::cout << t.size() << std::endl;
std::cout << t.back().print() << std::endl;
t.pop_back();
std::cout << t.size() << std::endl;
std::cout << t.back().print() << std::endl;
return 0;
}
Output:
2
2
1
1
3. Using smart pointers:
If you need to use pointers, use smart pointers (like std::unique_ptr, std::shared_ptr) instead of raw ones. The benefit is that the deallocation is done automatically.
std::unique_ptr is the more light-weight and should be the default one. Use std::shared_ptr if you need shared ownership.
Code example (with the same output as above):
#include <vector>
#include <iostream>
#include <memory>
struct T
{
T(int n) :x(n) {};
int print() { return x; };
private:
int x;
};
int main(int argv, char** argc)
{
std::vector<std::unique_ptr<T>> t;
t.push_back(std::make_unique<T>(1));
t.push_back(std::make_unique<T>(2));
std::cout << t.size() << std::endl;
std::cout << t.back()->print() << std::endl;
t.pop_back();
std::cout << t.size() << std::endl;
std::cout << t.back()->print() << std::endl;
return 0;
}
In your code there are two distinct types of objects to be considered.
The elements in the vector are pointers to T, T*. The lifetime of those pointers is managed by the vector. You can add or remove them via member methods of the vector.
Then there are the objects you decided to manage manually via the raw pointers in the vector. They are instances of T. Because you used new to create them you must use delete to delete them.
The vector cannot know about this relation between the pointers (the elements in the vector) and the T objects. It was your decision to manage them manually. You do not have to do that.
Chances are high that you either want a std::vector<T>. Or if for some reason (there is none in your code) you need to have the Ts allocated dynamically, then you would use a std::vector<std::unique_ptr<T>>.
Now this line:
delete t.back();
deletes the T, but the pointer is still in the vector. It is an invalid pointer, the object is was pointing to is no longer alive. When you call t.back()->print() your code invokes undefined behavior. You cannot use an already deleted object. If you do, anything can happen. This has nothing to do with the vector, it is similar to
T* t = new T(); // create object
delete t; // delete it
t->print(); // use it -> !!! undefined behavior !!!
Instead of this you should write
T t;
t.print();
In case you are coming from Java, you must unlearn to use new to create objects. The way to create objects in C++ is not via new.
My question is why i need delete and then remove , can't same
operation done in single command ?
There would be 6 answers from me to your question and Let this be your introduction to Pointers , Stack and the Heap.
1.) new operator "Allocates" memory on the heap not the stack,Create that Object (Using it's Constructors) then return a Pointer to the Object that is now on the Heap, hence the need for using the delete operator to "De-allocate" the memory you have requested and "Destroy" the created Object.
2.) delete "De-Allocates" the memory from heap and "Destroy" the created Object, and it does not remove it from the vector
3.)t.pop_back() will remove the Pointer element from the vector but will not de-allocate and Destroy the object the Pointer is Pointing too.
4.) It can't be done with one line since you have requested to allocate a Memory on the heap that can fit struct T inside via the new keyword. By using the keyword new the vector std::vector t is not storing an Object struct T,[std::vector<T>] instead storing Pointers to an Object of struct T [std::vector<T*>] since you did not explicitly Say what the Vector would Hold.
5.) Heap Allocated memory is perpetual , meaning it will always be there and labeled "In Use". Neither the Program, Runtime nor the O.S. can use it to allocate a new Memory Region on the heap unless you explicitly de-allocate and destroy it when using delete, Essentially saying "I'm done with this memory location thank you You may now destroy this object and re-use the memory)". or the Program Closes / Ends. So every new or new[] must be accompanied by delete or delete[] somewhere in the code when that variable is no longer in use anywhere in the program.
6.) After you understand the behavior of Heap / Dynamic Variables have a look at Smart Pointers. Which Handles the destruction of an object for you automatically. If you are coming from Managed Languages, you might want to read up on "Object Lifetimes" on C++.
The following Code will help you visualize my answer.
#include <vector>
#include <iostream>
struct T
{
T(int n):x(n){};
int print() {
return x;
};
// Replaces the Value of X
void SetX(int n){x=n;};
private:
int x;
};
int main(int argv,char** argc)
{
// We explicitly Say that the Vector is holding a Pointers to an object struct T
std::vector<T*> t;
// Insert New Elements to the Vector
t.push_back(new T(1));
t.push_back(new T(2));
// Will show that there are 2 elements in the vector.
std::cout << "Size of Vector Is " << t.size() << std::endl << std::endl;
// Assign the Last Element to a Pointer of T.
T* pointerToT = NULL;
pointerToT = t.back();
// Print the Memory Address and value of pointerToT and the Last Element
// And we can see they are the same location and holds the same value.
std::cout << "The Memory Location of pointerToT is " << pointerToT << std::endl;
std::cout << "The Memory Location of t.back() is " << t.back() << std::endl;
std::cout << "The Value of X in pointerToT is " << pointerToT->print() << std::endl;
std::cout << "The Value of X in t.back() is " << t.back()->print() <<std::endl << std::endl;
//Removes the Last Element of the Vector
t.pop_back();
// Will show that there is only 1 element in the vector.
std::cout << "Size of Vector Is " << t.size() << std::endl << std::endl;
// Print the Memory Address of pointerToT and the Value of X
// And as we can see pointerToT is still holding the same location
// and still holding the value 2, since the program knows that
// The memory Location is "Still" in use and not yet De-Allocated
// ready to be re-used and the object not yet destroyed.
std::cout << "The Value of X after pop_back() is " << pointerToT->print() << std::endl;
std::cout << "The Memory Location of pointerToT after pop_back is " << pointerToT << std::endl << std::endl;
//De-Allocate the Memory and Destroy the Object that was created by t.push_back(new T(2));
delete pointerToT;
// Prints the value of X, that is stored in the memory on the heap that it's pointing to.
// This Value may or may not be 2 if it is now used other parts of the Code
// which we call an Undefined Behaviour.
// On a Larger Program this could and would Cause a Segmentation fault or
// an Access Violation since this is now a Memory Region that is not explicitly
// Allocated for pointerToT , to the Member Variable X, nor
// The Last Element of the Vector and may now be in use by other variables and that the object is Destroyed already destroyed.
std::cout << "The Memory Location of pointerToT after delete is " << pointerToT << std::endl;
std::cout << "The Value of X after Delete is " << pointerToT->print() << std::endl;
// This is also an undefined Behaviour since you are now accessing and modifying
// a Memory Location that is not Allocated for pointerToT . But would show
// that the value of X is now 10. So only delete(Destroy)when you are sure you are not going to be
// accessing that variable again.
pointerToT->SetX(10);
std::cout << "The Value of X after SetX() is " << pointerToT->print() << std::endl;
return 0;
}
As the title describes, I am trying to pass the pointer to the data of a std::vector into a function expecting a double pointer. Take as an example the code below. I have an int pointer d which is passed to myfunc1 as &d (still not sure if call it the pointer's reference or what), where the function changes its reference to the beginning of an int array filled with 1,2,3,4. However, if I have a std::vector of ints and try to pass &(vec.data()) to myfunc1 the compiler throws the error lvalue required as unary ‘&’ operand. I have already tried something like (int *)&(vec.data()) as per this answer, but it does not work.
Just for reference, I know I can do something like myfunc2 where I directly pass the vector as reference and the job is done. But I want to know if it's possible to use myfunc1 with the std::vector's pointer.
Any help will be very much appreciated.
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
void myfunc1(int** ptr)
{
int* values = new int[4];
// Fill all the with data
for(auto& i:{0,1,2,3})
{
values[i] = i+1;
}
*ptr = values;
}
void myfunc2(vector<int> &vec)
{
int* values = new int[4];
// Fill all the with data
for(auto& i:{0,1,2,3})
{
values[i] = i+1;
}
vec.assign(values,values+4);
delete values;
}
int main()
{
// Create int pointer
int* d;
// This works. Reference of d pointing to the array
myfunc1(&d);
// Print values
for(auto& i:{0,1,2,3})
{
cout << d[i] << " ";
}
cout << endl;
// Creates the vector
vector<int> vec;
// This works. Data pointer of std::vector pointing to the array
myfunc2(vec);
// Print values
for (const auto &element : vec) cout << element << " ";
cout << endl;
// This does not work
vector<int> vec2;
vec2.resize(4);
myfunc1(&(vec2.data()));
// Print values
for (const auto &element : vec2) cout << element << " ";
cout << endl;
return 0;
}
EDIT: What my actual code does is to read some binary files from disk, and load parts of the buffer into the vector. I was having troubles getting the modified vector out of a read function, and this is what I came up with that allowed me to solve it.
When you write:
myfunc1(&(vec2.data()));
You are getting the address of a rvalue. The pointed int* is so a temporary that is destroyed right after the call.
This is why you get this error.
But, as #molbdnilo said, in your myfunc1() function, you are reassigning the pointer (without caring to destroy previously allocated memory by the way).
But the std::vector already manages its data memory on its own. You cannot and you must not put your hands on it.
What my actual code does is to read some binary files from disk, and load parts of the buffer into the vector.
A solution could be to construct your std::vector by passing the iterator to the beginning and the iterator to the end of the desired part to extract in the constructor's parameters.
For example:
int * buffer = readAll("path/to/my/file"); // Let's assume the readAll() function exists for this example
// If you want to extract from element 5 to element 9 of the buffer
std::vector<int> vec(buffer+5, buffer+9);
If the std::vector already exists, you can use the assign() member function as you already did in myfunc2():
vec.assign(buffer+5, buffer+9);
Of course in both cases, you have to ensure that you are not trying to access an out of bounds element when accessing the buffer.
The problem is that you cannot take the address of data(), since it is only a temporary copy of the pointer, so writing to a pointer to it makes not that much sense. And that is good that way. You DO NOT want to pass data() to this function since it would overwrite the pointer with a new array and that would break the vector. You can remove one * from the function and only assign to it and not allocate the memory there. This will work, but make sure to allocate the memory in the caller (with resize, just reserve will result un undefined behavior, since data() is only a pointer to the beginning of the valid range [data(), data() + size()). The range [data(), data() + capacity ()) is not necessary valid.
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
I'm learning about pointers and I can't get this code to work. Here's what I have so far:
void incrementArray(int* a[]) {
for(auto& x : a) {
++x;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int array[] = {0,1,2,3,4,5,6,7,8,9};
for(auto x : array) {
cout << x << '\n';
}
incrementArray(&array);
for(auto x : array) {
cout << x << '\n';
}
}
I'm getting the following error:
'incrementArray' : cannot convert parameter 1 from 'int (*)[10]' to
'int *[]'
What can I do to fix my code?
C-style arrays have funny syntax. To pass the array to a function, use int a[] This does not copy the array and changes to the array inside the function will modify the external array. You only need to call incrementArray(array); no & needed
You could try using std::array class which follows more normal syntax.
you have a pointer as a parameter (a reference to an array), but you wish to modify the actual thing it's pointing to, so you gotta change *a, not a.
You could use an array, vector, list, etc object that would have methods already associated to them that do most of the manipulation you could want
What you are trying to do will not work since the signature of a function taking int a[] as an argument does not contain the necessary length information needed to write a for-each loop (i.e. to instantiate the begin() and end() templates needed to use the for-each syntax). GCC's warning says this fairly clearly:
Error:(14, 19) cannot build range expression with array function parameter 'a' since
parameter with array type 'int *[]' is treated as pointer type 'int **'
I thought this might be do-able with a template, but . . .
EDIT:
It can be done with templates, just took me a moment to wrap my head around the syntax. Here is your example in working condition:
template <size_t N>
void incArray(int (&a)[N]) {
for(auto& x : a) {
++x;
}
}
int main(int argc, const char * argv[])
{
int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto x : array) {
cout << x << " ";
}
cout << endl;
incArray(array);
for (auto x : array) {
cout << x << " ";
}
cout << endl;
return 0;
}
There are a couple approaches you could take to increment the elements of an array, all of which require knowing where to start and where to end. The simple way of doing what you want is to just pass the start and end address pointers, but you could also pass a start address with some offset. Since you are using a C-Style array, your int element has and address int*, so your std::begin(array) is an int* to the first element while std::end(array) points to the address of the location after your last allocated element. In your program, the std::end() address points to the memory location after your 10th allocated element. If you had an array with a size allocation (int other_arr[40]), std::end() will point to the first address after the allocation (std::end(other_arr) would be std::begin(other_arr)+41). C++ has recently introduced non-member std::begin() and std::end() in the <iterator> library, which returns a pointer to the respective element locations in your C-Array.
#include <algorithm> // std::copy
#include <iostream> // std::cout
#include <iterator> // std::begin
void increment_elements(int* begin, const int* end) {
while (begin != end) {
++(*begin);
++begin;
}
}
// An increment functor for std::transform
int increase_element(int i) {
return ++i;
}
int main() {
int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (const int x : array) {
std::cout << x << ' ';
}
std::cout << '\n';
increment_elements(std::begin(array), std::end(array));
// Another way to write your print statement above
std::copy(std::begin(array),
std::end(array),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
// Transform array elements through increase_element()
// and print result to cout.
std::transform(std::begin(array),
std::end(array),
std::ostream_iterator<int>(std::cout, " "),
increase_element);
std::cout << '\n';
}
The generalized version of the increment_elements() function can be found in the <algorithm> library as the function std::transform() documented here.
Since you are learning now, here are some habits that you can start to utilize:
Do not use using namespace std; at the global level. By pulling everything in the standard library into the global namespace, you "pollute" it with functionality that can be called if a function call for it exists, since it doesn't require a std:: prefix qualification. Say you were to write a function that calculated the euclidean distance between two (x,y) points, double distance(Point* p1, Point* p2). You decide to use any of the STL containers, such as <vector>. The containers utilize the <iterator> library, which has its own std::distance(T*, T*) function to calculate the distance between two addresses in memory. By bringing std into the global namespace by using namespace std;, you now have 2 functions with the same signature in the same namespace, that do 2 completely different things. This is very bad yet easily avoidable. This general guideline is probably unnecessary for small projects, but I still recommend you just don't ever do it for any project. Ever.
const or const T& your read only operations. When doing operations where you are pulling data for reading and you don't want to modify the data, initialize using const or const T&. const by itself is sufficient for primitive datatypes (int, float, double, char), but non-primitives will require const T& (T is the type). Values that are of type const T& (called const referenced) are read-only (const) and directly accessed (&).
I'm trying to create an array of classes using a vector, but I think I'm getting the syntax wrong from instantiating the array. The error I'm getting is:
error: request for member 'setX' in objects[0], which is of non-class type 'std::vector'
#include <iostream>
#include <vector>
using std::cout;
class A {
public:
void setX(int a) { x = a; }
int getX() { return x; }
private:
int x;
};
int main() {
std::vector<A> *objects[1];
objects[0].setX(5);
objects[1].setX(6);
cout << "object[0].getX() = " << objects[0].getX() << "\nobject[1].getX() = " << objects[1].getX() << std::endl;
}
std::vector<A> objects; // declare a vector of objects of type A
objects.push_back(A()); // add one object of type A to that vector
objects[0].setX(5); // call method on the first element of the vector
With an asterisk and a square brackets, you are declaring an array of pointers to vectors instead of a vector. With std::vector<T> you do not need square brackets or an asterisk:
std::vector<A> objects(2); // 2 is the number of elements; Valid indexes are 0..1, 2 is excluded
objects[0].setX(5); // This will work
objects[1].setX(6);
The reason the compiler thought that you were trying to call setX on a vector is that the square bracket operator, overloaded by the vector, is also a valid operator on an array or a pointer.
An array and std::vector are two completely different container types. An array is actually a fixed-size block of memory, where-as a std:vector object is a dynamic sequential container type, meaning it can be dynamically "grown" and "shrunk" at run-time, and the object itself manages the memory allocation of the objects it owns. Their apparent similarities are that both can access members in O(1) complexity and can use the bracket syntax for accessing members.
What you want is something like the following:
int main()
{
//make a call to the std::vector<T> cstor to create a vector that contains
//two objects of type A
std::vector<A> objects(2);
//you can now access those objects in the std::vector through bracket-syntax
objects[0].setX(5);
objects[1].setX(6);
cout << "object[0].getX() = " << objects[0].getX() << "\nobject[1].getX() = " << objects[1].getX() << std::endl;
return 0;
}
here what you did is define an array with 1 element of type std::vector*, you may want to read more about vector and array first.
The correct way to define it is:
std::vector<A> objects(2);
or using pointers if that is what you intend to
std::vector<A*> objects(2);
objects[0] = new A();
objects[1] = new A();