C++: Default Arguments and Vectors - c++

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).

Related

How to create a reference to any class implementing square bracket operator?

I use std::vector<double> in some of my logic, but mainly the operator[]. Some data is coming from google's protocol buffer library in a repeated field. An example for the proto file:
message My_message{
repeated double numbers = 1;
}
So far I've only been using vectors, and converted the protobuf field to vector as described in another question.
void my_function(const std::vector<double> my_numbers){
...
double i_shall_copy_this = my_numbers[0];
std::copy(my_numbers.begin(),my_numbers.end(), inside_vector.begin());
...
}
int main(){
My_message my_msg;
...
std::vector<double> my_vec = {my_msg.numbers().begin(),my_msg.numbers().end()};
my_function(my_vec);
return 0;
}
Unfortunately this comes with unnecessary copying of data, which I would like to avoid. To avoid copying I would like to use references.
void my_function(const std::vector<double>& my_numbers){
...
}
int main(){
My_message my_msg;
...
my_function({my_msg.numbers().begin(),my_msg.numbers().end()}); //(1)
my_function(reinterpret_cast<std::vector<double>>(my_msg.numbers())); //(2)
return 0;
}
So far, adding it by temporary works( //(1) ), but it involves copying.
Despite the fact that both google::protobuf::RepeatedField and std::vecDor implements operator[], a reinterpret cast have failed //(2) :
error: invalid cast from type ‘const google::protobuf::RepeatedField<double>’ to type ‘std::vector<double>’
So a solution I have been thinking about is to add a third type, which requires only operator[] and the iterators implemented ( and a contiguous guarantee ).
Unfortunately common inheritance is not an option here: Both types come from official libraries, and I am just a mortal unworthy of maintaining a fork of those for a project. What options do I have here?
This is what templates are for. Since you only need the passed in type to have an operator[], you can make the function a template:
template<typename Container>
void my_function(const Container & my_numbers) {
// use my_numbers[42] for example
}
and now this will compile for any type that has operator[] defined for it.
So now there is no need to convert the google::protobuf::RepeatedField<double> to a temporary std::vector<double>.

Known array / pointer size as argument

InputManager* input = new InputManager(new int[]{ SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT });
I wanna pass this array of keys (or a pointer to it) but i need the InputManager's constructor to know its size. Since its known at compile time how would i get it?
Online i found this template
template <int N>
InputManager::InputManager(int (&keyArray)[N]) {
this->maxKeys = N;
this->keys = keyArray;
}
But i get an error that the arguments dont match.
I need any possible solution where i dont need to manually write the length. So macros, templates or anything else is accepted.
Don't use so many pointers. It's not healthy and you're likely to either leak memory, or try to free memory that you can't (if you didn't pass a newly-allocated array). Here's a minimal modification of your code:
class InputManager {
public:
template <int N>
InputManager(int (&keyArray)[N])
: maxKeys(N), keys(std::make_unique<int[]>(N))
{
std::copy_n(keyArray, N, keys.get());
}
private:
std::size_t maxKeys;
std::unique_ptr<int[]> keys;
};
int main() {
int keys[] = { 1, 5, 4, 7, 2 };
InputManager input {keys};
}
This compiles (GodBolt).
Notes:
This way, you don't need to write a custom destructor; although you would need to write an assignment operator which copies data; and a copy constructor.
It's probably better to just use an std::vector internally (or std::array if you know the input size beforehand), and take any span or range of keys in the constructor.
Wrap creating of this array into function using variadic template.
If you want only return a pointer to array:
template<class ... enums>
int* makeArray (enums ... e) {
return new int[sizeof...(e)]{e...};
}
When you want to know size of returned array you can return pair:
template<class ... enums>
std::pair< int*, size_t > makeArray2(enums ... e) {
constexpr size_t N = sizeof...(e);
return std::make_pair( new int[N]{e...}, N);
}

constructing a std::vector using std::transform. Possibility to return unnamed result?

Let's have
class InputClass;
class OutputClass;
OutputClass const In2Out(InputClass const &in)
{
//conversion implemented
}
and finally
std::vector<OutputClass> Convert(std::vector<InputClass> const &input)
{
std::vector<OutputClass> res;
res.reserve(input.size());
//either
for (auto const &in : input)
res.emplace_back(In2Out(in));
return res;
//or something like
std::transform(input.begin(), input.end(), std::back_inserter(res), [](InputClass const &in){return In2Out(in);});
return res;
}
And now my question:
Can I rewrite the Convert function somehow avoiding the need to name the new container? I. e. is there a way to construct a vector directly using something roughly like std::transform or std::for_each?
As in (pseudocode, this unsurprisingly does not work or even build)
std::vector<OutputClass> Convert(std::vector<InputClass> const &input)
{
return std::transform(input.begin(), input.end(), std::back_inserter(std::vector<OutputClass>()), [](InputClass const &in){return In2Out(in);});
}
Searched, but did not find any elegant solution. Thanks!
Starting in C++ 20 you can use the new std::ranges::transform_view to accomplish what you want. It will call your transformation function for each element in the container that it is adapting and you can use that view to invoke std::vector's iterator range constructor which will allocate the memory for the entire vector once and then populate the elements. It still requires you to create a variable in the function but it becomes much more streamlined. That would give you something like
std::vector<OutputClass> Convert(std::vector<InputClass> const &input)
{
auto range = std::ranges::transform_view(input, In2Out);
return {range.begin(), range.end()};
}
Do note that this should optimize to the exact same code your function generates.
Yes it is possible, and quite simple when using boost:
struct A
{
};
struct B
{
};
std::vector<B> Convert(const std::vector<A> &input)
{
auto trans = [](const A&) { return B{}; };
return { boost::make_transform_iterator(input.begin(), trans), boost::make_transform_iterator(input.end(), trans) };
}
https://wandbox.org/permlink/ZSqt2SbsHeY8V0mt
But as other mentioned this is weird and doesn't provide any gain (no performance gain or readability gain)
Can I rewrite the Convert function somehow avoiding the need to name the new container?
Not using just std::transform. std::transform itself never creates a container. It only inserts elements to an output iterator. And in order to both get output iterator to a container, and return the container later, you pretty much need a name (unless you allocate the container dynamically, which would be silly and inefficient).
You can of course write a function that uses std::transform, creates the (named) vector, and returns it. Then caller of that function doesn't need to care about that name. In fact, that's pretty much what your function Convert is.

C++ - dynamically use either reference or local variable

I would like to do something like this (I'm aware that this won't compile):
struct Container{
vector<int> storage;
};
float foo(Container* aContainer){
if(aContainer!=NULL)
vector<int>& workingStorage=aContainer->storage;
else
vector<int> workingStorage;
workingStorage.reserve(1000000);
....use workingStorage to calculate something......
return calculated_result;
}
So - if i pass a Container to the function, i want that the function uses the vector in the container to work with instead of a local variable. If no container is provided, it should use a local variable.
of course I could just in the end of the function copy the local variable to the storage of the Container, but that's not what I want to do.
Thanks!
Create a local std::vector<int> named local_storage for the case where a container is not provided by the caller, then create a reference to whatever container you are actually going to use.
std::vector<int> local_storage;
std::vector<int>& working_storage = aContainer
? aContainer->storage
: local_storage;
One way to approach this problem is to break the function foo into 2 functions
float foo(Container* aContainer){
if(aContainer!=NULL) {
return foo_core(aContainer->storage);
} else {
vector<int> workingStorage;
return foo_core(workingStorage);
}
float foo_core(vector<int>& workingStorage) {
...
// rest of original foo
}
vector<int> temp;
vector<int>& workingStorage = (aContainer!=NULL) ? aContainer->storage : temp;
The design is apparently horrible. But given that an optional externally provided storage is what you want, JaredPar (his answer) has a good idea. Cleaning that further up:
struct Container
{
vector<int> storage;
};
double foo( vector<int>& workingStorage )
{
workingStorage.reserve( 1000000 );
//....use workingStorage to calculate something......
return calculated_result;
}
double foo( Container& storageProvider )
{
return foo( storageProvider.storage );
}
double foo()
{
vector<int> storage;
return foo( storage );
}
Cheers & hth.,
Why don't you make sure that aContainer->storage is initialized before you pass aContainer it to foo. That makes your code lot more neater. Have an assert statement at the start of the function to check aContainer->storage for NULL.

Extracting a reference from a c++ vector

I have a vector< vector< vector< int>>> and I would like to extract from it a vector< vector< int>> to process it individually.
The problem is that when I write :
myMatrix = myCube[anIndex];
the matrix is copied but I only want a reference in order to save memory.
Can you please help me out ?
Thanks a lot!
Just use
vector<vector<int> >& myMatrix = myCube[anIndex];
Use an Iterator of type vector< vector< int> >::const_iterator. Hope this helps.
vector::operator[] returns a reference - as long as you store that result into a reference instead of a full-blown object you should avoid a copy.
vector< vector<int > >& myMatrix = myCube[anIndex];
If myMatrix is a class member and you want to be able to initialise it outside the constructor, your only choice is using a pointer:
class Whatever
{
//...
vector<vector<int>>* myMatrix;
//...
}
myMatrix = &myCube[anIndex]
EDIT: If you can live with initialising myMatrix in the constructor, you can use a reference:
class Whatever
{
//...
vector<vector<int> >& myMatrix;
//...
}
Whatever::Whatever(vector<vector<vector<int> > >& myCube), int anIndex)
: myMatrix(myCube[anIndex])
{
//...
}
Incidentally, you have to separate the > in your code, unless you are using a C++0x conformant compiler; otherwise, the compiler will parse the >> as operator>> and give you an error.
Instead of using operator[] use functions returning iterators as advance, and declare the matrix as follows
vector< vector< int> >::iterator myMatrixPtr;
myMatrixPtr = std::advance(myCube, anIndex);
Now you are able to work with myMatrixPtr as if it were a pointer. If you prefer a reference you can initialize one after this initialization
vector< vector<int > >& myMatrix = *myMatrixPtr;
Be careful with member references! If the referred-to object is cleaned up before the instance of MyClass is, you will have an invalid reference. Often (but not always), if you find that you need to use a member reference, it is an early warning sign that your design could be improved. I rarely use member references for anything other than as a handle to an object's owner, where I can be absolutely certain that the referred-to object will outlive the reference.
It might help if you change slightly your class' responsibilities. Right now, you are building up a set of data, and then creating an object to which you pass that set of data. Instead, why not first build the object, then put the data directly into it.
// To start, define your class to allow you to build up the data
class MyMatrix
{
public:
MyMatrix ()
{ }
void setData (int x, int y, int data)
{ this->myData [x][y] = data; }
int getData (int x, int y)
{ return this->myData [x][y]; }
private:
vector<vector<int> > myData;
}
// Then, create a vector of 6 (or however many you need) matrices
int numberOfMatrices = 6;
vector<MyMatrix> myCube (numberOfMatrices);
// Then, fill in the vector
for (int matrixIndex = 0; matrixIndex < numberOfMatrices; matrixIndex++)
{
// Fill in the data for this matrix
MyMatrix &currentMatrix = myCube [matrixIndex];
currentMatrix.setData (0 /* x */, 0 /* y */, 0 /* data */);
// ... rest of data
}
Then, you have all the data already in your objects, ready to be processed as you need. Plus, each object owns its data, so as long as the object is around, its member data will be valid. Best of all, using objects with usefully named member functions will make your code much more self-documenting than tons of nested containers.