c++ method address vector - c++

I'm new at using vector, I need a method that return the addres of the vector, this is the semplifide code:
class:
#include<vector>
class A
{
private:
std::vector<int> v;
public:
A()
{
for (int i = 0; i < 5; i++)
v[i] = i;
}
std::vector<int> give()
{
return v;
}
~A() {}
};
main:
#include <iostream>
#include "class.cpp"
int main(int argc, char **argv)
{
A a;
int *vptr = NULL;
vptr = &a.give()[0];
std::vector<int> b;
return 0;
}
this code compile but during the execution a segmentation fault is given

This constructor
A(){
for(int i = 0; i < 5; i++)
v[i] = i;
}
is invalid because the vector has no yet elements that you could use the subscript operator. More correctly would be to write
A() : v( 5 ) {
for(int i = 0; i < 5; i++)
v[i] = i;
}
As for your question then std::vector has member function data that returns the address of its internal buffer with elements.
So you could write
int * give(){ return v.data(); }
or
const int * give() const { return v.data(); }
In main you could write
int *vptr = a.give();

You have several big problems here.
First, in the constructor you're trying to access elements of the vector that don't yet exist:
A(){
for(int i = 0; i < 5; i++)
v[i] = i;
}
vector isn't the same as map where if the element you are looking for with operator[] doesn't exist a new one is created. In vector if you use operator[] with an index that doesn't exist you get Undefined Behavior, and a verly likely crash. You should be inserting items here. On way is push_back:
A(){
for (int i = 0; i < 5; ++i)
v.push_back (i);
}
Next, give() returns a vector by-value:
std::vector<int> give(){
return v;
}
Which makes a copy of v and returns that copy. Well that's technically OK, but when you call give() you don't assign the return value to a variable. What ends up happening is the copy of the vector becomes a temporary object. As soon as the so-called "full-expression" where the temporary was created is done, the temporary is destroyed.
That full-expression is this:
vptr = &a.give()[0];
So, vptr was assigned the address of the first element of that temporary vector, but as soon as the end of this expression is reached that vector is destroyed and vptr now points to hyperspace. If you attempt to dereference this wild pointer, you get Undefined Behavior and a very likely segmentation fault.
To fix this, you could let A tell you the address of the first element of the vector:
class A
{
// [...]
public:
void* give() { return v.data(); }
};

Related

Why std::vectors is not destroyed from the stack as array?

When we use arrays and pointers this way:
int *g() {
int arr[] = {1, 2, 3};
return arr;
}
int f() {
int *value = g();
for (size_t i = 0; i < 3; i++) {
std::cout << value[i] << " ";
}
std::cout << std::endl;
}
int main(int argc, const char **argv) {
f();
return 0;
}
It is deleted from the stack after function g returns, so we get a segment error in the function f()
But using std::vector this same logic works without any problem:
std::vector<int> g() {
std::vector<int> arr = {1, 2, 3};
return arr;
}
int f() {
std::vector<int> value = g();
for (size_t i = 0; i < value.size(); i++) {
std::cout << value.at(i) << " ";
}
std::cout << std::endl;
}
int main(int argc, const char **argv) {
f();
return 0;
}
I was thinking that this is something related to the fact that we have the std::vector class acting as a container to the array but using a struct as a container delete the array either:
struct T {
int *arr;
};
T g() {
T t;
int arr[] = {1, 2, 3};
t.arr = arr;
return t;
}
int f() {
T value = g();
for (size_t i = 0; i < 3; i++) {
std::cout << value.arr[i] << " ";
}
std::cout << std::endl;
}
int main(int argc, const char **argv) {
f();
return 0;
}
And in this case, g++ allow us to overflow the array pointer memory limits with the index subscription.
Why vectors doesn't share the same problem?
All the elements in the vector essentially count as part of the vector. And notice you are returning the vector, not a pointer to the vector. But you are returning a pointer to (the start of) the array.
When the function g returns, the vector arr is destroyed but that's okay because that's not the same one that is returned. A copy of arr is returned. (Actually, the compiler is clever enough to reuse the same vector instead of copying it and then deleting one - but you can imagine that it makes a copy)
Then f prints values from its own local variable value - no problem.
By contrast, in the pointer version, f is printing values from the local variable arr inside g, which has already been destroyed. If g would return a pointer to a vector, it would have the same problem.
Your intuition was somewhat right it has something to do with the containment of the array inside a struct, what you misunderstand however is the difference between (int[]) and (int*) and probably you don't understand well where memory resides as well.
To clarify:
In C++ C-style array types (int[]), (char[]) etc cannot be returned from a function.
Your function does not return (int[]) it returns int* which is a pointer that points to an an (int[]'s zero element in the stack space of some function f() ) and hence the existence of this (int[]) stops past the lifetime of the function f(), but a dangling pointer was copied to the caller's site;
Try
using int_array = int[4];
int_array f()
{
int_array arr { 1, 2, 3, 4};
return arr; // Does not compile cannot return array
}
int* f2()
{
int_array arr { 1, 2, 3, 4};
return arr; // Compiles because int[4] is implicitly cast to int*
}
In the case of vector, it contains a pointer to a dynamically allocated memory block, acquired through some means(new, malloc, custom user defined allocator, etc) hence this memory block is not bound to the lifetime of a function call, but it is managed by the owner of it. When you return the vector to the caller, the memory block behind continues to exist until a (delete, free, custom-delete) is called on it. The vector does this in it's destructor ( ~vector() ), but before that happening a vector( const vector& ) constructor call occurs that copies the content of one vector to the other. Most compilers will optimize away this operation, as mentioned by another answer.
In the case where you return the struct, the problem is the same, you are not returning an array (int[]) you are returning a pointer. If you were to contain an array inside the struct it would be successfully copied back to caller, because the restriction only applies for arrays and not for user defined types.
Try:
struct Foo {
int arr[4];
};
Foo f()
{
Foo obj{ 1, 2, 3, 4 }; // brace initialization of struct
return obj;
}
int main()
{
Foo obj = f();
for(int i = 0; i < 4; i++)
std::cout << i << ' '; // outputs 1 2 3 4 with no issues
}
As you can see no issues with memory here. That's why the std::array<> from header exists - to wrap C-Style arrays so they can be copied over.
I hope this explains well enough.
In the second method returning vector<int>. The std::vector<int> arr was copied to another a temporary vector<int>, then std::vector<int> arr was destroyed.
Finally, the vector<int> value was assigned with temporary vector<int>, after assigning completed, temporary vector<int> was destroyed as well.
That's what i think happening with your example.

Items of std::array are changed unintentionally out of context

I'm trying passing the reference of array to class object by constructor, and operating the items in that object.
But, I'm afraid that these items in array are changed just after reaching at the beginning of MySort::sort() below. (not changed before entering MySort::sort())
#include <iostream>
#include <utility>
#include <array>
using namespace std;
template <typename T>
struct MySort
{
T &_n;
size_t _s;
public:
MySort(T n) : _n(n)
{
_s = _n.size();
}
void sort()
{
for (size_t i = 0; i < _s - 1; i++)
{
for (size_t j = i + 1; j < _s; j++)
{
if (_n[i] > _n[j])
std::swap(_n[i], _n[j]);
}
}
cout << "teste" << endl;
}
friend ostream &operator<<(ostream &ost, const MySort &c)
{
for (size_t i = 0; i < c._s; i++)
ost << c._n[i];
return ost;
}
};
int main(int argc, const char **argv)
{
array<int, 5> numbers{2, 5, 1, 7, 3};
MySort<array<int, 5>> bubble{numbers};
bubble.sort();
cout << bubble << endl;
return 0;
}
In the case of passing array by copy, It works correctly.
Thank you for your attention.
The constructor
MySort(T n) : _n(n)
{
_s = _n.size();
}
Here you set _n to reference a input object which will get destroyed upon leaving the constructor. This is plain UB.
To fix it write
MySort(T& n) : _n(n)
{
_s = _n.size();
}
In the constructor MySort(T n), you are making a copy of the array, then storing a reference to the copy, but then the copy goes out of scope, so you have a dangling reference.
If you want to use a reference, you should pass a reference to the original object, MySort(T &n), and make sure that the original object is always in scope during the lifetime of the MySort object.

References to elements in vectors during construction

In C++, I have a class MyClass, which during construction takes a reference to an int to create an internal reference to it.
I then have a class BigClass, containing both an std::vector<int> vecInt_ and an std::vector<MyClass> vecMyClass_. The constructor of BigClass takes as an argument the size of the vectors vecInt_ and vecMyClass_. In the constructor of BigClass, I would like to have each element of vecMyClass_ use in its constructor the corresponding element of vecInt_.
How could I write that ? If I could call the constructors of vecMyClass from the body of the constructor of BigClass, that would look like that :
BigClass(int nbElem) :
vecInt_(nbElem),
vecMyClass_(nbElem)
{
for (int i = 0; i < nbElem; ++i)
{
vecMyClass_[i](vecMyInt_[i]);
}
}
But of course the parenthesis here would mean operator(), and not the constructor. I cannot write something like:
vecMyClass_[i] = MyClass(vecMyInt_[i]);
Because MyClass contains a reference and not a pointer, and thus referenced value can not be modified.
You could initialize vecMyClass_ as an empty vector and emplace_back elements into it while you construct them:
BigClass(int nbElem) :
vecInt_(nbElem),
vecMyClass_() //empty vector
{
vecMyClass_.reserve(nbElem); //avoid reallocations
for (int i = 0; i < nbElem; ++i)
{
vecMyClass_.emplace_back(vecInt_[i]);
}
}
It doesn't sound like a very good idea. At some point adding elements to vecMyInt_ will result in expanding the vector, i.e. allocating new memory and moving the elements there, and freeing the old memory. This means that the references kept by instances of MyClass will be invalid.
Of course this won't be a problem if you reserve the capacity beforehand, and never add elements to the vector.
#include <vector>
#include <iostream>
struct MyClass {
int& x;
MyClass(int& x) : x(x) {}
};
struct BigClass {
BigClass(std::size_t nb_elems) : ints(nb_elems) {
my_classes.reserve(nb_elems);
for(int& x : ints) {
my_classes.emplace_back(x);
}
}
std::vector<int> ints;
std::vector<MyClass> my_classes;
};
int main()
{
BigClass b{10};
for(int& x : b.ints) {
x = 23;
}
// they are all 23
for(auto& c : b.my_classes) {
std::cout << c.x << std::endl;
// change them
c.x = 24;
}
// they are all 24 now
for(auto& c : b.ints) {
std::cout << c << std::endl;
}
return 0;
}

Array memory Allocation doesn't work

I have the next classes:
class A {
};
class B : public A {
int num;
};
in my main I have:
int main() {
A* vec; // A is a class with pure virtual functions
vec = new B[2]; // want to create a vector of B
}
vec[0] is defined correctly, but vec[1] is NULL. why didn't it allocate me a fit memory?
I don't want to change the lines of the main. just make it working.
(I know I can change the main into: B* vec = new B[2] but I don't want)
any help appreciated!
You cannot treat arrays polymorphically, the C++ language does not support it. The expression vec[x] uses pointer arithmetic to determine the location of the element. If you are accessing it through a base class pointer it will not work if the size of the objects vary in any way.
For example, you have base class that is 4 bytes in size and the subclass is 8 bytes in size.
base *a = new child[4];
When you access a[1] the compiler calculates the offset using the size of the base class. In this case the offset is 4 bytes which ends up pointing to the middle of the first element.
I recommend using a std::vector or std::array of pointers with an appropriate smart pointer.
// For arrays that needs to be resized (requires delete for each new)
std::vector<A*> vec(5, NULL);
for(int i = 0; i < vec.size(); i++)
{
vec[i] = new B();
}
// for arrays that are fixed in size (requires delete for each new)
std::array<A*, 5> vec;
for(int i = 0; i < vec.size(); i++)
{
vec[i] = new B();
}
// for arrays that are fixed in size with smart pointers
// no delete needed
std::array<std::unique_ptr<A>, 5> vec;
for(int i = 0; i < vec.size(); i++)
{
vec[i].reset(new B());
}
if you would like it to be polymorphic just create an array of pointers
new A*[array_size]
This code snippet illustrates the problem you are having.
#include <iostream>
using namespace std;
class A {
};
class B : public A {
int num;
};
int main() {
A* vec; // A is a class with pure virtual functions
vec = new B[2]; // want to create a vector of B
cout << sizeof(vec) << endl;
cout << sizeof(*vec) << endl;
cout << sizeof(vec[2]) << endl;
cout << sizeof(new B()) << endl;
}
In pointer arrithmetic, the size of the type of the pointer you allocated is what is used for incrementing, not the size of the true type of the object it is pointing to. More simply, the language does not support polymorphic arrays. This is simply an explanation of why.

Destructor not called when returning a local instance [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Why is the destructor not called for the returned object from the function?
I wrote some C++ code (below), compiled it with GCC 4.6 and it ran successfully. But I don't know why the destructor of classA isn't called when returning from createA().
Since ca is a local variable in createA() (i.e. on the stack), I think its destructor should be called when returning from the function. But in fact, the destructor is only called once when returning from the main function.
Moreover, returning a local instance always works fine in this test. I wonder if it's safe to return a local instance on a stack frame when the frame has been popped out after returning.
This is my code:
#include <iostream>
#include <string.h>
class classA
{
public:
classA() { len = 0; v = 0; }
classA(int a)
{
len = a;
v = new int[a];
for (int i = 0; i < a; i++)
v[i] = 2*i;
}
~classA()
{
if (v)
{
memset(v, 0, len * sizeof(int));
delete [] v;
}
}
int *v;
int len;
};
classA createA(int a)
{
classA ca(a);
return ca;
}
using namespace std;
int main()
{
int a = 10;
classA ca = createA(a);
classA *pca = &ca;
for (int i = 0; i < a; i++)
cout << pca->v[i];
cout << endl;
return 0;
}
This is called return value optimization.
In short, the compiler doesn't have to return a copy of the object to optimize the code.
For ca is a local variable, i.e. on the stack [...]
Not necessarily. ca can be created directly in the calling context to prevent the extra copy. Copy elision is the only optimization that a compiler is free to perform that can alter expected behavior.