Initialisation of static vector - c++

I wonder if there is the "nicer" way of initialising a static vector than below?
class Foo
{
static std::vector<int> MyVector;
Foo()
{
if (MyVector.empty())
{
MyVector.push_back(4);
MyVector.push_back(17);
MyVector.push_back(20);
}
}
}
It's an example code :)
The values in push_back() are declared independly; not in array or something.
Edit: if it isn't possible, tell me that also :)

In C++03, the easiest way was to use a factory function:
std::vector<int> MakeVector()
{
std::vector v;
v.push_back(4);
v.push_back(17);
v.push_back(20);
return v;
}
std::vector Foo::MyVector = MakeVector(); // can be const if you like
"Return value optimisation" should mean that the array is filled in place, and not copied, if that is a concern. Alternatively, you could initialise from an array:
int a[] = {4,17,20};
std::vector Foo::MyVector(a, a + (sizeof a / sizeof a[0]));
If you don't mind using a non-standard library, you can use Boost.Assignment:
#include <boost/assign/list_of.hpp>
std::vector Foo::MyVector = boost::list_of(4,17,20);
In C++11 or later, you can use brace-initialisation:
std::vector Foo::MyVector = {4,17,20};

With C++11:
//The static keyword is only used with the declaration of a static member,
//inside the class definition, not with the definition of that static member:
std::vector<int> Foo::MyVector = {4, 17, 20};

Typically, I have a class for constructing containers that I use (like this one from boost), such that you can do:
const list<int> primes = list_of(2)(3)(5)(7)(11);
That way, you can make the static const as well, to avoid accidental modifications.
For a static, you could define this in the .cc file:
// Foo.h
class Foo {
static const vector<int> something;
}
// Foo.cc
const vector<int> Foo::something = list_of(3)(5);
In C++Ox, we'll have a language mechanism to do this, using initializer lists, so you could just do:
const vector<int> primes({2, 3, 5, 7, 11});
See here.

You could try this one:
int arr[] = { 1,2,3,4,5,6,7,8,9 };
MyVector.insert(MyVector.begin(), arr, &arr[sizeof(arr)/ sizeof(*arr)]);
But it's probably only worth when you have a really long vector, and it doesn't look much nicer, either. However, you get rid of the repeated push_back() calls. Of course, if your values are "not in an array" you'd have to put them into there first, but you'd be able to do that statically (or at least references/pointers), depending on the context.

How about initializing using a static object. In its constuctor it
could call a static function in the object to do the initalization.

with boost you can use the +=() operator defined in the boost::assign namespace.
#include <boost/assign.hpp>
using namespace boost::assign;
int main()
{
static std::vector<int> MyVector;
MyVector += 4,17,20;
return 0;
}
or with static initialization:
#include <boost/assign.hpp>
using namespace boost::assign;
static std::vector<int> myVector = list_of(4)(17)(2);
int main()
{
return 0;
}
or even better, if your compiler supports C++ 11, use initialization lists.

Related

Using a temporary object without storing it in variable

Let's take an example where we need to insert the vector returned from a function to another vector:
const std::vector<int> getvec(){
return {1, 2, 3};
}
// in main...
std::vector<int> foo{ 11, 12 };
auto bar = getvec();
foo.insert(foo.end(), bar.begin(), bar.end());
The fact that the bar variable needs to be referenced twice in the insert() method makes it necessary to have the vector stored as a variable (we could otherwise do foo.myinsert(getvec()) should there be such an interface).
It is a bit annoying to me that in such a case, we need to introduce a variable foo in the main scope which is not meant to be used again in the rest of the code, as it occupies the memory and also pollutes the namespace. Especially a problem if we are talking about with a large "temporary" object.
Is there a standard approach to deal with that? We could define a function that take the "temporary" object only once so that we can directly feed function output to it, but would be difficult to manage if we need to define such function for every similar scenario. Also as in this example we are not able to define a member function for vector class.
Alternatively what using braces to limit the scope of the "temporary" part of the insertion but I would like to know if any caveat here.
vector<int> foo{ 11, 12 };
{ // extra brace here
auto bar = getvec();
foo.insert(foo.end(), bar.begin(), bar.end());
} // extra brace here
Not the prettiest solution, but you could use a temporary lambda instead of a separate function, and declaring and invoking it in the same statement avoids the need for braces to limit its scope.
const std::vector<int> getvec(){
return {1, 2, 3};
}
// in main...
std::vector<int> foo{ 11, 12 };
[&](const auto &bar){ foo.insert(foo.end(), bar.begin(), bar.end()); }(getvec());
Live Demo
You could write a little template function to do this, which takes a vector by const reference (which can bind to a temporary and extend its lifetime):
template<typename C>
void append(std::vector<C> &invec, const std::vector<C> &temp)
{
invec.insert(std::end(invec), std::begin(temp), std::end(temp));
}
and this could be used for all other types of vectors. Then you can call it like this:
append(foo, getvec());
Working demo here.
You can make strings of other things than char. Thru basic_string<int> you can access string::append ( and other things )
using strint = std::basic_string<int>;
strint getVec () {
return { 1, 2, 3, 4, 5 };
}
strint foo{ 6, 7 };
foo += getVec();
https://godbolt.org/z/h4naTa

Moving an std::unordered_map values to std::vector

Is there any way to move unordered_map values to a vector? All the ways I was able to find copy values (like in my example) instead of using something similar to std::move.
I would like to not copy values so I can retain uniqueness of shared_ptr foo, which I'll later change to unique_ptr.
class Class {
public:
std::shared_ptr <int> foo = std::shared_ptr <int> (new int (5));
};
int main() {
std::unordered_map <int, Class> mapOfObjects({
{1, Class()},
{2, Class()},
{3, Class()},
{4, Class()},
{5, Class()} });
std::vector <Class> someVector;
for (auto &object : mapOfObjects) {
someVector.push_back(object.second);
std::cout << "Is unique? " << ( someVector.back().foo.unique() ? "Yes." : "No.")
<< std::endl << std::endl;
}
}
Thank you in advance for all helpful answers.
You can certainly move shared_ptr from unordered_map to vector. All you need to do is to use std::move in your example:
someVector.push_back(std::move(object.second));
Keep in mind, after this operation, you might want to clear the map, as it now contains empty objects.
#SergeyA's answer already covers the essential part here, let me nevertheless add a solution based on range-v3, it shows where one part of the language is heading to with C++20.
#include <range/v3/view/map.hpp>
#include <range/v3/view/move.hpp>
using namespace ranges;
/* Setup mapOfObjects... */
const std::vector<Class> someVector = mapOfObjects | view::values | view::move;
The STL in its current shape isn't that bad either, but admittetly more verbose:
#include <algorithm>
#include <iterator>
std::vector<Class> someVector;
std::transform(std::move_iterator(mapOfObjects.begin()),
std::move_iterator(mapOfObjects.end()),
std::back_inserter(someVector),
[](std::pair<int, Class>&& entry){ return std::move(entry.second); });

Return a pointer to 2D array from a function - C++

So what I am trying to achieve is to return a pointer to a 2D array from the function so it could accessed in main(). I know there are some C++ libraries that does it for you like std::vector but I am trying to avoid dynamic memory allocation since I am working on embedded board (STM32) so I will stick to just normal pointers and arrays. (ALSO for some reason I can't use std::array in KEIL uVision, which is also why I am forced to work with pointers/arrays)
In addition, I understand that returning a pointer to a local array int arr[2][2] defined inside the function is not a good idea since it will no longer be valid after the function returns, which is why I creating test_array, declaring it inside a class and defining it in a function (acting as a global variable) so I assume this shouldn't be a problem. What do you guys think? However, doing it this way gives an error "Excess elements in scalar initializer"
#include <iostream>
#include "file.hpp"
int main() {
myClass class_object;
class_object.value = class_object.foo();
}
//file.hpp
#include <stdio.h>
class myClass{
int array[2][2];
int (*foo())[2];
int (*value)[2];
int test_array[2][2]; //declaring here!
};
//file.cpp
#include "file.hpp"
int (*myClass::foo())[2]{
test_array[2][2]={ {10,20}, {30, 40} }; //defining here - ERROR!!
int arr[2][2]= {
{1, 10},
{20, 30}
};
return arr;
}
The immediate problem:
test_array[2][2]={ {10,20}, {30, 40} }; //defining here - ERROR!!
is not defining. test_array was defined up in myClass. This is attempting to assign to a single element of test_array, specifically [2][2] which does not exist. What particularly offends the compiler is not the out of bounds access, but that ={ {10,20}, {30, 40} }; is trying to stuff an array into a single array element. The compiler is expecting a single number, so four numbers is definitely in excess.
Unfortunately I don't know of a good way to do what you want to do. You can initialize an array with an initializer list, but you can't assign from one.
So
class myClass{
public:
myClass();
void foo();
int test_array[2][2]; //declaring here!
};
// you can do this:
myClass::myClass(): test_array{ {10,20}, {30, 40} }
{
}
void myClass::foo()
{
// but you can't do this:
test_array = { {10,20}, {30, 40} };
}
Depending on what you do with test_array, initializing in the constructor may work for you. If you have to reset the array on every call to foo, perhaps an Automatic variable is a better fit for you
void myClass::foo()
{
int temp_array[2][2] = { {10,20}, {30, 40} };
// use temp_array
// maybe copy temp_array to test_array with good ol' memcpy here if you
// need to carry the state for some reason.
}
To silence the elephant in the room and gain access to std::array, give this a try. Note: I've never done this. It could be an utter freaking disaster for all I know, so take it with a grain of salt.
If you really want to work with C-Array, use typedef to have normal syntax:
class myClass{
public:
using array2 = int[2][2];
myClass() {
test_array[0][0] = 0;
test_array[0][1] = 1;
test_array[1][0] = 2;
test_array[1][1] = 3;
}
const array2& getArray() const { return test_array; }
array2& getArray() { return test_array; }
private:
array2 test_array;
};

Best way to return and assign a vector in c++ between multiple functions [duplicate]

This question already has answers here:
Why is it OK to return a 'vector' from a function?
(6 answers)
Closed 6 years ago.
I am hoping to get a newly generated vector and add into a global vector from calling two functions in main. I have a rough idea of how to do this but apparently this is not right..pretty new to c++ and I don't really quite want to deal with vector recycle..do I have to use pointers if I can't use C++11? what's the best way to do this?
void main(){
vector <int> newVector = function1 ();
addVector (newVector);
}
vector <int> function1 (){
....
return returnedVector
}
void addVectors (vector <int> incomingVector){
globalVector.insert( globalVector.end(), incomingVector.begin(), incomingVector.end());
}
First off, void main() in c++ is bad - it should be int main().
Secondly, you have the statement return vector; in function1() whilst you are likely using namespace std; - this is also very bad, as it can be interpreted as attempting to return a type which is not possible nor what you want to do.
Here is a refactoring of your code:
#include <vector>
std::vector<int> function1(); // declaration
void add_vectors(std::vector<int>& ov, const std::vector<int>& iv);
int main() {
std::vector<int> overall_vec;
std::vector<int> vec = function1();
add_vector(overall_vec, vec);
}
std::vector<int> function1() { // definition
std::vector<int> rtnvec;
// fill rtnvec with some values
return rtnvec;
}
// insert incoming_vec to end of overall_vec
void add_vectors(std::vector<int>& overall_vec, const std::vector<int>& incoming_vec) {
overall_vec.insert(overall_vector.end(), incoming_vec.begin(), incoming_vec.end());
}
Note that we haven't used a global std::vector variable here as global variables are generally quite bad, it's typically better to pass the vector around by reference or const reference when and if you need to - or wrap your code in a class or namespace if the situation is suitable for either.

C++: Default Arguments and Vectors

In C++, I want to have a function that takes an optional argument of type vector. If the argument is not provided, I want the variable to have size 0. I currently have
void v_connect::import(vector<int> vid_,vector<double> vpos_,vector<int> vbd_,vector<int> bd_ss_=std::vector<int>() )
But this doesn't work. Basically, if the user provides the optional argument bd_ss_ I want to do a check bd_ss_.size()!=0 and then do some extra stuff. If the user does not provide the argument, I want bd_ss.size()==0. Is this possible?
There is no way to tell whether or not an optional argument is user-provided. However, you could use an overload:
void v_connect::import(
std::vector<int> vid_,
std::vector<double> vpos_,
std::vector<int> vbd_,
std::vector<int> bd_ss_)
{
check(!bd_ss_.empty());
do_extra_stuff();
do_import(vid_, cpos_, vbd_, bd_ss_);
}
void v_connect::import(
std::vector<int> vid_,
std::vector<double> vpos_,
std::vector<int> vbd_)
{
do_import(vid_, cpos_, vbd_, std::vector<int>());
}
// private:
void v_connect::do_import(
std::vector<int> vid_,
std::vector<double> vpos_,
std::vector<int> vbd_,
std::vector<int> bd_ss_)
{
// common import code goes here
}
You could make the user pass a pointer instead:
void foo(std::vector<int> * ov = NULL)
{
std::vector<int> dummy;
std::vector<int> & bd_ss_ = ov ? *ov : dummy;
if (ov) assert(!bd_ss_.empty());
// ...
}
Alternatively, use Boost.optional, which is a clever C++-style wrapper around this idea and allows you to have the same behaviour with a seamless interface.
Optional parameters go in the header, not the cpp.
As an aside you're mixing vector and std::vector, use one or the other (prefer to stick to std::vector).