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
Related
Suppose I have some object with an initial name such as quantities_of_widgets.
std::vector<int> quantities_of_widgets = GetQuantities();
I then perform an operation on quantities_of_widgets in-place. The vector quantities_of_widgets no longer represents "a vector of some quantities of things called widgets".
PerformOperationInPlace(quantities_of_widgets);
After this operation, a more appropriate name for the variable would be weights_of_widgets. That would certainly make the code more readable.
I can "change" the name by moving quantities_of_widgets to a new vector weights_of_widgets. This is a terrible idea. The move isn't free, it messes with memory continuity, etc.
std::vector<int> weights_of_widgets = std::move(quantities_of_widgets);
I could also document the meaning of the variable in comments. I might write
std::vector<int> widgets = GetQuantities(); // widgets represents quantities
PerformOperationInPlace(widgets); // widgets represents weights
UseWeights(widgets);
However, comments are less permanent and less readable. It becomes more difficult to keep track of the meaning of variables over multiple lines of code. If widgets is used 20 lines down in the middle of a large expression, I'd have trouble documenting the meaning of the variable at that point.
SomeBigFunction(Func1(widgets, some_other_object_1), some_other_object_2);
I could try aliasing, but I want to make the old name invalid to help with maintainability. Is there a way to change the name of a variable with no run-time cost?
Worrying about such small overhead is almost certainly not worth the effort in all but the most extreme scenarios. However, for the sake of completeness:
The only way to get truly overhead-free renaming of types with non-trivial destructors is via copy-elision.
In this context, you could make use of it via an immediately evaluated lambda and NRVO.
#include <vector>
std::vector<int> GetQuantities(int v);
void PerformOperationInPlace(std::vector<int>&);
void UseWeights(const std::vector<int>&);
template<typename T>
T rename(T&& rhs) {
return rhs;
}
void foo(int x) {
std::vector<int> quantities_of_widgets = GetQuantities(x);
PerformOperationInPlace(quantities_of_widgets);
UseWeights(quantities_of_widgets);
}
void bar(int x) {
std::vector<int> weights_of_widgets = [&]{
std::vector<int> quantities_of_widgets = GetQuantities(x);
PerformOperationInPlace(quantities_of_widgets);
return quantities_of_widgets;
}();
UseWeights(weights_of_widgets);
}
foo() and bar() compile down to effectively the exact same final assembly: (see on godbolt)
The only limitation is that the variable that will be renamed has to be declared within the lambda. Beyond that, implicit capture by reference makes the lambda effectively the same thing as a scope.
It is best to document code by itself. Comments have tendency do degrade.
So I would do this this way:
// name of this function terrible, it should be more like
// ExtractWeightsOfWidgetsFrom or something similar
std::vector<int> OperationInPlace(std::vector<int> data) {
// note argument is a copy!
....
return data;
}
void someCode() {
auto quantities_of_widgets = GetQuantities();
...
auto weights_of_widgets = PerformOperationInPlace(std::move(quantities_of_widgets));
// here `quantities_of_widgets` is empty since contents has been moved
// many tools will report an error if you use this value after that point
....
}
or even better I would just extract more functions:
void someCode() {
auto quantities_of_widgets = GetQuantities();
...
ProcesWeightsOfWidgets(
PerformOperationInPlace(std::move(quantities_of_widgets));
// in this version someCode ends here
}
Suppose I have a class MyClass:
class MyClass{
private:
vector<vector<float>> _vec;
public:
MyClass(vector<vector<float>> arg){
_vec = arg;
// shape is a 2-element vector where shape[0] = #elems in _vec
// and shape[1] = #elems in _vec[0]
shape.push_back(_vec.size());
shape.push_back(_vec.begin()->size());
}
vector<int> shape;
};
Now suppose I have a member function func of MyClass:
MyClass MyClass::func(){
MyClass res(this->_vec);
// delete the first element of `res._vec`
res._vec.erase(res._vec.begin());
return res;
}
Now, if I do:
MyClass A = {{1, 2}, {3, 4}}; // A.shape[0] = 2, A.shape[1] = 2
MyClass B = A.func(); // B._vec is {{3, 4}} but B.shape[0] is still 2
Here, B._vec changes, but B.shape is not "updated" accordingly.
How can I dynamically update MyClass.shape as and when MyClass._vec changes? One way to do this is to instead make a member function MyClass.shape() which whenever called checks the current MyClass._vec. But is there a better way of doing this?
How can I dynamically update MyClass.shape as and when MyClass._vec changes?
Write a function that updates shape, and call it whenever you change _vec.
But is there a better way of doing this?
Don't use shape member at all, but instead call _vec.size() and _vec.begin()->size() when you need those values. This way there is nothing to update, no redundant duplicate waste of memory, and the user of the class cannot break the apparently missing invariant.
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).
I have a vector (order is important) of objects (lets call them myobj class) where I'm trying to delete multiple objects at a time.
class vectorList
{
vector<*myobj> myList;
};
class myobj
{
char* myName;
int index;
bool m_bMarkedDelete;
}
I was thinking that the best way to do this would be to mark specific myobj objects for deletion and then call myList.remove_if() on the vector. However, I'm not exactly sure how to use predicates and such for this. Should I create a member variable in the object which allows me to say that I want to delete the myobj and then create a predicate which checks to see if the member variable was set?
How do I implement the predicate as a part of the vectorList class?
Should I create a member variable in the object which allows me to say
that I want to delete the myobj and then create a predicate which
checks to see if the member variable was set?
Haven't you already done that? Isn't that what m_bMarkedDelete is for? You would write the predicate like this:
bool IsMarkedToDelete(const myobj & o)
{
return o.m_bMarkedDelete;
}
Then:
myList.erase(
std::remove_if(myList.begin(), myList.end(), IsMarkedToDelete),
myList.end());
Or, using lambdas:
myList.erase(
std::remove_if(myList.begin(), myList.end(),
[](const myobj & o) { return o.m_bMarkedDelete; }),
myList.end());
If your class doesn't actually have that member, and you're asking us if it should, then I would say no. What criteria did you use to decide to mark it for deletion? Use that same criteria in your predicate, for example:
bool IndexGreaterThanTen(const myobj & o)
{
return o.index > 10;
}
note -- The functions I've written are of course invalid since all your members are private. So you'll need some way to access them.
A predicate is basically a conditional comparison. It can be a function or object. Here's an example using new C++ lambdas. This code will go through the vector and remove the values equal to 3.
int arg[6] = {1, 2, 3, 3, 3, 5};
std::vector<int> vec(arg, arg+6);
vec.erase(
std::remove_if(
vec.begin(), vec.end(),
[](int i){ return i == 3;}),
vec.end());
Edit: For pointers let's say you had a vector or interfaces you could set them to nullptr then remove them in a batch with pretty much the same code. In VS2008 you won't have lambdas so make a comparison predicate function or struct instead.
bool ShouldDelete(IAbstractBase* i)
{
return i == nullptr;
// you can put whatever you want here like:
// return i->m_bMarkedDelete;
}
std::vector<IAbstractBase*> vec;
vec.erase(
std::remove_if(
vec.begin(), vec.end(),
ShouldDelete),
vec.end());
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.