See the code below:
#include <vector>
#include <iostream>
int main(int argc, char *argv[]) {
std::vector<double> obj(10,0);
std::cout << &obj << std::endl;
std::cout << &obj[0] << std::endl;
}
I want to know the difference between these two addresses & thanks!
As I know, for a array like a[5], &a <=> &a[0] <=> a.
&obj is the address of the vector itself, while the &obj[0] is the address of the data inside the vector.
Arrays are nothing but data stored in them, so adress of array is effectively the same as adress of the data in it, while vector allocates its internal data on heap.
Maybe this helps
struct MyVector
{
double* data;
};
int main
{
MyVector obj;
cout << &obj << std::endl;
cout << obj.data << std::endl;
}
Obviously (I hope) the two pointers are different. It's just the same with std::vector.
&obj is the address of the vector on the stack. It's type is "pointer to vector" ( std::vector* ). While &obj[0] is the address of the very first double stored in the vector and is of type "pointer to double" (double*).
I have the feeling you misunderstand the very basic difference between std::vector and the array. What I mean is, for example
int i_array [ 5 ] = { 0 };
is not what the vector is. The vector is a class, and i_array is solely a pointer to the first integer of the array. ( And using [] on a pointer is not the same as using [] on the vector object )
While using the [] operator of vector, you are just accessing a function of the class which returns a reference to the first integer ( or double in your case ) of an array which is managed by the class vector.
So &obj gives you the pointer for your instance of the vector, your object, "this", while &obj[0] first calls operator [] which returns a reference to the first entry of your array, and with & you get the address of it.
Related
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 want to work out how to use old style pointer arithmetic on pointers to elements of the std::array class. The following code (unsurprisingly perhaps) does not compile:
int main(int argc, char *argv[])
{
double* data1 = new double[(int)std::pow(2,20)];
std::cout << *data1 << " " << *(data1 +1) << std::endl;
delete data1;
data1 = NULL;
double* data2 = new std::array<double, (int)std::pow(2,20)>;
std::cout << *data2 << " " << *(data2 +1) << std::endl;
delete data2;
data2 = NULL;
return 0;
}
As an exercise, I want to use all the conventional pointer arithmetic, but instead of pointing at an old style double array, I want it to point to the elements of a std::array. My thinking with this line:
double* data2 = new std::array<double, (int)std::pow(2,20)>;
is to instruct the compiler that data2 is a pointer to the first element of the heap allocated std::array<double,(int)std::pow(2,20)>.
I have been taught that the double* name = new double[size]; means EXACTLY the following: «Stack allocate memory for a pointer to ONE double and name the pointer name, then heap allocate an array of doubles of size size, then set the pointer to point to the first element of the array.» Since the above code does not compile, I must have been taught something incorrect since the same syntax doesnt work for std::arrays.
This raises a couple of questions:
What is the actual meaning of the statement type* name = new othertype[size];?
How can I achieve what I want using std::array?
Finally, how can I achieve the same using std::unqiue_ptr and std::make_unique?
I have been taught that the double* name = new double[size]; means EXACTLY the following: «Stack allocate memory for a pointer to ONE double and name the pointer name, then heap allocate an array of doubles of size size, then set the pointer to point to the first element of the array.» Since the above code does not compile, I must have been taught something incorrect since the same syntax doesnt work for std::arrays.
You are correct about that statement, but keep in mind that the way this works is that new[] is a different operator from new. When you dynamically allocate an std::array, you're calling the single-object new, and the returned pointer points to the std::array object itself.
You can do pointer arithmetic on the contents of an std::array. For example, data2.data() + 1 is a pointer to data2[1]. Note that you have to call .data() to get a pointer to the underlying array.
Anyway, don't dynamically allocate std::array objects. Avoid dynamic allocation if possible, but if you need it, then use std::vector.
Can we use conventional pointer arithmetic with std::array?
Yes, sure you can - but not on the array itself, which is an object. Rather, you use the address of the data within the array, which you get with the std::array's data() method, like so:
std::array<double, 2> data2 { 12.3, 45.6 };
double* raw_data2 = data2.data(); // or &(*data2.begin());
std::cout << *raw_data2 << " " << *(raw_data2 + 1) << std::endl;
and this compiles and runs fine. But you probably don't really need to use pointer arithmetic and could just write your code different, utilizing the nicer abstraction of an std::array.
PS - Avoid using explicit memory allocation with new and delete(see the C++ Core Guidelines item about this issue). In your case you don't need heap allocation at all - just like you don't need it with the regular array.
You can have access to the "raw pointer" view of std::array using the data() member function. However, the point of std::array is that you don't have to do this:
int main(int argc, char *argv[])
{
std::array<double, 2> myArray;
double* data = myArray.data();
// Note that the builtin a[b] operator is exactly the same as
// doing *(a+b).
// But you can just use the overloaded operator[] of std::array.
// All of these thus print the same thing:
std::cout << *(data) << " " << *(data+1) << std::endl;
std::cout << data[0] << " " << data[1] << std::endl;
std::cout << myArray[0] << " " << myArray[1] << std::endl;
return 0;
}
The meaning of a generalized:
type* name = new othertype[size];
Ends up being "I need a variable name that's a pointer to type and initialize that with a contiguous allocation of size instances of othertype using new[]". Note that this involves casting and might not even work as othertype and type might not support that operation. A std::array of double is not equivalent to a pointer to double. It's a pointer to a std::array, period, but if you want to pretend that's a double and you don't mind if your program crashes due to undefined behaviour you can proceed. Your compiler should warn you here, and if it doesn't your warnings aren't strict enough.
Standard Library containers are all about iterators, not pointers, and especially not pointer arithmetic. Iterators are far more flexible and capable than pointers, they can handle exotic data structures like linked lists, trees and more without imposing a lot of overhead on the caller.
Some containers like std::vector and std::array support "random access iterators" which are a form of direct pointer-like access to their contents: a[1] and so on. Read the documentation of any given container carefully as some permit this, and many don't.
Remember that "variable" and "allocated on stack" are not necessarily the same thing. An optimizing compiler can and will put that pointer wherever it wants, including registers instead of memory, or nowhere at all if it thinks it can get away with it without breaking the expressed behaviour of your code.
If you want std::array, which you really do as Standard Library containers are almost always better than C-style arrays:
std::array<double, 2> data2;
If you need to share this structure you'll need to consider if the expense of using std::unique_ptr is worth it. The memory footprint of this thing will be tiny and copying it will be trivial, so it's pointless to engage a relatively expensive memory management function.
If you're passing around a larger structure, consider using a reference instead and locate the structure in the most central data structure you have so it doesn't need to be copied by design.
Sure, these are all legal:
template<class T, std::size_t N>
T* alloc_array_as_ptr() {
auto* arr = new std::array<T,N>;
if (!arr) return nullptr;
return arr->data();
}
template<class T, std::size_t N>
T* placement_array_as_ptr( void* ptr ) {
auto* arr = ::new(ptr) std::array<T,N>;
return arr->data();
}
template<std::size_t N, class T>
std::array<T, N>* ptr_as_array( T* in ) {
if (!in) return nullptr;
return reinterpret_cast<std::array<T,N>*>(in); // legal if created with either above 2 functions!
}
// does not delete!
template<std::size_t N, class T>
void destroy_array_as_ptr( T* t ) {
if (!t) return;
ptr_as_array<N>(t)->~std::array<T,N>();
}
// deletes
template<std::size_t N, class T>
void delete_array_as_ptr(T* t) {
delete ptr_as_array<N>(t);
}
the above is, shockingly, actually legal if used perfectly. The pointer-to-first-element-of-array is pointer interconvertable with the entire std::array.
You do have to keep track of the array size yourself.
I wouldn't advise doing this.
std::array is a STL container after all!
auto storage = std::array<double, 1 << 20>{};
auto data = storage.begin();
std::cout << *data << " " << *(data + 1) << std::endl;
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.
so let's say there is a function int* coeff(int n) that returns array (or rather, address to array[0]). Now, in this function this array has length of let's say 5, but when I call it like: int* array=SomeObject->coeff(n); that size is lost, and I don't know how can I get it back again. Any help please?
If you actually return a locally declared you have bigger problem than "losing its size".
First of all you have to remember that arrays decays to pointers, and once it has done that you no longer have any information about the array, just the pointer. And the size of a pointer is the size of the pointer and not what it points to.
The bigger problem might be you returning a locally declared array. When a function returns all variables declared locally in it goes out of scope. So what does the returned pointer then point to?
I assume your code looks something like this:
int* coeff(int n)
{
int* a = new int[5];
// ...
return a;
}
I suggest using a vector instead of an array:
#include <vector>
std::vector<int> coeff(int n)
{
std::vector<int> a(5);
// ...
return a;
}
You can always get the size of a vector by calling the .size() member function:
int main()
{
std::vector<int> x = coeff(42);
std::cout << x.size() << " elements in the vector!\n";
}
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();