How to initialized Pointer of Vector c++? - c++

The following code is not working :
vector< vector<int> > *te = new vector< vector<int> >();
(*te)[0].push_back(10);
cout << (*te)[0][0];
How should I initialize it ?

I do not see a sense in dynamic allocation of the vector nevertheless a correct syntax can look like
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int> > *pv = new std::vector<std::vector<int> >;
pv->push_back( std::vector<int>( 1, 10 ) );
std::cout << ( *pv )[0][0] << std::endl;
delete pv;
}
The output is
10

std::vector<std::vector<int>>* te = new std::vector<std::vector<int>>();
This line isn't you're problem. However, it does beg the question "Why are you dynamically allocating a std::vector?"
(*te)[0].push_back(10);
This line is your problem. You're accessing the 0th index of te but it's empty (i.e., doing this invokes undefined behavior). You need to add something to it first: te->push_back(std::vector<int>());.
Example Code
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>>* te = new std::vector<std::vector<int>>();
// Add an empty `vector` to `te`
te->push_back(std::vector<int>());
// Add `10` to the first `vector` in `te` and print it
(*te)[0].push_back(10);
std::cout << (*te)[0][0];
delete te;
return 0;
}
Note: You should also be in the habit of using smart pointers and not worry about manually newing and deleting the memory (e.g., std::unique_ptr pointer and std::make_unique).

Related

Copy vector of vectors into 1D array

I have following C++ object
std::vector<std::vector<SomeClass>> someClassVectors(sizeOFOuter);
where I know the size of "outer" vector, but sizes of "inner" vectors varies. I need to copy the elements of this structure into 1D array like this:
SomeClass * someClassArray;
I have a solution where I use std::copy like this
int count = 0;
for (int i = 0; i < sizeOfOuter; i++)
{
std::copy(someClassVectors[i].begin(), someClassVectors[i].end(), &someClassArray[count]);
count += someClassVectors[i].size();
}
but the class includes large matrices which means I cannot have the "vectors" structure and 1D array allocated twice at the same time.
Any ideas?
Do you previously preallocate someClassArray to a given size? I'd suggest using 1D vector for getting rid of known problems with the plain array if possible.
what about something like this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<std::vector<int>> someClassVectors {
{1,2,3},
{4,5,6},
{7,8,9}
};
std::vector<int> flat;
while (!someClassVectors.empty())
{
auto& last = someClassVectors.back();
std::move(std::rbegin(last), std::rend(last), std::back_inserter(flat));
someClassVectors.pop_back();
}
std::reverse(std::begin(flat), std::end(flat));
int * someClassArray = flat.data();
std::copy(someClassArray, someClassArray + flat.size(), std::ostream_iterator<int>(std::cout, " "));
}
The extra reverse operation doesn't have an effect on memory metrics - such an approach helps to avoid unneeded memory reallocations resulting from removing vector elements from beginning to end.
EDIT
Inspired by comments I changed copy to move semantics
Embrace Range-v3 (or whatever will be introduced in C++20) and write a solution in (almost) a single line:
auto flattenedRange = ranges::views::join(someClassVectors);
this gives you a range in flattenedRange, which you can loop over or copy somewhere else easily.
This is a possible use case:
#include <iostream>
#include <vector>
#include <range/v3/view/join.hpp>
int main()
{
std::vector<std::vector<int>> Ints2D = {
{1,2,3},
{4},
{5,6}
};
auto Ints1D = ranges::views::join(Ints2D);
// here, going from Ints1D to a C-style array is easy, and shown in the other answer already
for (auto const& Int : Ints1D) {
std::cout << Int << ' ';
}
std::cout << '\n';
// output is: 1 2 3 4 5 6
}
In case you want to get a true std::vector instead of a range, before writing it into a C-style array, you can include this other header
#include <range/v3/range/conversion.hpp>
and pipe join's output into a conversion function:
auto Ints1D = ranges::views::join(Ints2D) | ranges::to_vector;
// auto deduces std::vector<int>
In terms of standard and versions, it doesn't really require much. In this demo you can see that it compiles and runs just fine with
compiler GCC 7.3
library Range-v3 0.9.1
C++14 standard (option -std=c++14 to g++)
As regards the copies
ranges::views::join(Ints2D) is only creating a view on Ints2D, so no copy happens; if view doesn't make sense to you, you might want to give a look at Chapter 7 from Functional Programming in C++, which has a very clear explanation of ranges, with pictures and everything;¹
even assigning that output to a variable, auto Ints1D = ranges::views::join(Ints2D);, does not trigger a copy; Ints1D in this case is not a std::vector<int>, even though it behaves as one when we loop on it (behaves as a vector because it's a view on it);
converting it to a vector, e.g. via | ranges::to_vector, obviously triggers a copy, because you are no more requesting a view on a vector, but a true one;
passing the range to an algorithm which loops on its elements doesn't trigger a copy.
Here's an example code that you can try out:
// STL
#include <iostream>
#include <vector>
// Boost and Range-v3
#include <boost/range/algorithm/for_each.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/range/conversion.hpp>
struct A {
A() = default;
A(A const&) { std::cout << "copy ctor\n"; };
};
int main()
{
std::vector<std::vector<A>> Ints2D = {
{A{},A{}},
{A{},A{}}
};
using boost::range::for_each;
using ranges::to_vector;
using ranges::views::join;
std::cout << "no copy, because you're happy with the range\n";
auto Ints1Dview = join(Ints2D);
std::cout << "copy, because you want a true vector\n";
auto Ints1D = join(Ints2D) | to_vector;
std::cout << "copy, despite the refernce, because you need a true vector\n";
auto const& Ints1Dref = join(Ints2D) | to_vector;
std::cout << "no copy, because we movedd\n";
auto const& Ints1Dref_ = join(std::move(Ints2D)) | to_vector;
std::cout << "no copy\n";
for_each(join(Ints2D), [](auto const&){ std::cout << "hello\n"; });
}
¹ In an attempt to try giving a clue of what a range is, I would say that you can imagine it as a thing wrapping two iterators, one poiting to the end of the range, the other one pointing to the begin of the range, the latter being incrementable via operator++; this opearator will take care of the jumps in the correct way, for instance, after viewing the element 3 in Ints2D (which is in Ints2D[0][2]), operator++ will make the iterator jump to view the elment Ints[1][0].

C++ Using naked, instead of smart pointers

Consider the following code.
#include <iostream>
#include <vector>
#include <memory>
int main() {
std::vector<std::string> vec;
for(int i =0;i<10;i++){
vec.push_back("adsf");
}
std::string* myPoint = &vec[1];
*myPoint = "this works";
std::shared_ptr<std::string> str_ptr = std::make_shared<std::string>(vec[0]);
str_ptr->push_back('this does not push_back to the end of the string stored in at vec[0]');
for(int i =0;i<10;i++){
std::cout << vec[i] << std::endl; //does not print the new value set by str_ptr
}
return 0;
}
What I want here is to update a value in vec through a pointer. As I've understood smart pointers are no good for this task. Is using a naked pointer here, an acceptable alternative?
make_shared does not mean "make this already-existing thing be shared".
It means "make a new shared thing with the following constructor arguments".
You're dynamically allocating a new string that copies vec[0] (i.e. using the copy constructor).
If you want vec[0] to be a shared_ptr<string>, then you need to make it one from the start.

C++11 transform with shared_ptr to a vector and class

I am trying to apply transform to a shared_ptr and store to a shared_ptr while also using a function in a class.
I created this example:
#include <vector>
#include <iostream>
#include <memory>
#include <algorithm>
using namespace std;
class MyClass {
public:
int factor = 0;
MyClass(const int factor_) : factor(factor_) {}
shared_ptr<vector<int> > mult(shared_ptr<vector<int> > numbers) {
shared_ptr<vector<int> > result(new vector<int>() );
transform(numbers->begin(), numbers->end(), result->begin(),
[this](int x){ return factor * x; });
return result;
}
};
int main()
{
shared_ptr<vector<int> > numbers(new vector<int>());
shared_ptr<vector<int> > res(new vector<int>());
MyClass times_two(2);
numbers->push_back(1);
numbers->push_back(2);
numbers->push_back(3);
res = times_two.mult(numbers);
cout << "{";
for (unsigned int i = 0; i < res->size(); ++i)
cout << res->at(i) << ", ";
cout << "}";
return 0;
}
As can be seen here this causes a segmentation dump. Any help on how I could resolve this so that the output yields {2, 4, 6, }?
Note that I use the lambda because I need it in my full implementation.
I tried also to replace,
transform(numbers->begin(), numbers->end(), result->begin(),
[this](int x){ return factor * x; });
with
transform((*numbers).begin(), (*numbers).end(), (*result).begin(),
[this](int x){ return factor * x; });
shared_ptr<vector<int> > result(new vector<int>() );
You construct a new, empty vector.
transform(numbers->begin(), numbers->end(), result->begin(),
[this](int x){ return factor * x; });
Since result is empty, result->begin() returns the ending iterator value. std::transform copies the input sequence, applies the transformation lambda, and writes the transformed result to the output iterator.
Since the vector is empty, there's nothing to write to. You're running past the end of the empty array, resulting in undefined behavior and memory corruption.
In this case, simply preallocate the output array, since you know what its size should be, in advance:
shared_ptr<vector<int> > result(new vector<int>(numbers->size()) );
Now, this will create the output array of the correct size, begin() will return an iterator to the beginning of the array, and std::transform() will happily scribble over the array.
If you really wish to avoid the extra overhead of value-initializing the new array, just to have it overwritten, you can use reserve() to preallocate the array's final size, then use a std::back_insert_iterator for the output iterator, instead of passing in begin().

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.

Converting a vector to an array - Is there a 'standard' way to do this?

I know you can just do: &theVector[0], but is this standard? Is this behavior always guaranteed?
If not, is there a better, less 'hackish' way to do this?
Yes, that behavior is guaranteed. Although I can't quote it, the standard guarantees that vector elements are stored consecutively in memory to allow this.
There is one exception though:
It will not work for vector<bool> because of a template specialization.
http://en.wikipedia.org/wiki/Sequence_container_%28C%2B%2B%29#Specialization_for_bool
This specialization attempts to save memory by packing bools together in a bit-field. However, it breaks some semantics and as such, &theVector[0] on a vector<bool> will not work.
In any case, vector<bool> is widely considered to be a mistake so the alternative is to use std::deque<bool> instead.
C++11 provides the data() method on std::vector which returns a T*. This allows you to do:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vector = {1,2,3,4,5};
int* array = vector.data();
std::cout << array[4] << std::endl; //Prints '5'
}
However, doing this (or any of the methods mentioned above) can be dangerous as the pointer could become invalid if the vector is resized. This can be shown with:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vector = {1,2,3,4,5};
int* array = vector.data();
vector.resize(100); //This will reserve more memory and move the internal array
//This _may_ end up taking the place of the old array
std::vector<int> other = {6,7,8,9,10};
std::cout << array[4] << std::endl; //_May_ now print '10'
}
This could could crash or do just about anything so be careful using this.
We can do this using data() method. C++11 provides this method.
It returns a pointer to the first element in the vector. vector Even if it is empty, we can call this function itself without problems
vector<int>v;
int *arr = v.data();
A less 'hackish' way? Well you could simply copy :
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vect0r;
int array[100];
//Fill vector
for(int i = 0; i < 10 ; i++) vect0r.push_back( i ) ;
//Copy vector to array[ ]
for( i = 0; i < vect0r.size(); i++) array[i] = vect0r[i];
//Dispay array[ ]
for( i = 0; i < vect0r.size(); i++) cout<< array[i] <<" \n";
cout<<" \n";
return 0;
}
More here : How to convert vector to array in C++