I'm writing a function that will separate a vector of objects into two vectors depending on the value of one of their objects. I want it then to return whichever of the vectors.
This is the code I have so far
std::vector<AggregatedQuoteType> OrderBook::get_aggregated_order_book(SellBuyType which_side) const
{
std::vector<AggregatedQuoteType> ret;
std::vector<AggregatedQuoteType>::const_iterator i = v_OrderInfo.begin();
for (; i != v_OrderInfo.end(); ++i)
((*i).get_SB_type()==BUY ? v_BuyOrders : v_SellOrders).push_back((*i));
if(which_side==SELL){
ret = v_SellOrders;
}
else{
ret = v_BuyOrders;
}
return ret;
}
EDIT
I'm getting the following error:
[Error] no matching function for call to 'std::vector::push_back(const AggregatedQuoteType&) const'
You have marked your function get_aggregated_order_book as const.
OrderBook::get_aggregated_order_book(SellBuyType which_side) const
^^^^^
Here!
The const keyword in C++ implies that you will not be making changes to any members in your class, which I presume v_BuyOrders and v_SellOrders are.
If you're modifying the members of your OrderBook class, you need to make the method non-const.
Do you need the v_BuyOrders and v_SellOrders populated at all or just return whatever matches which_side? If the latter, how about just applying a copy_if operation and return the result?
std::vector<AggregatedQuoteType> ret;
std::copy_if(v_OrderInfo.cbegin(), v_OrderInfo.cend(), std::back_inserter(ret),
[=](const AggregatedQuoteType &at) { return at.get_SB_type() == which_side) };
return ret;
EDIT: not using lambda/C++11,
struct pred {
SellBuyType type;
pred(SellBuyType t) : type(t) {}
bool operator()(const AggregatedQuoteType &at) {
return at.get_SB_type() != type; // Copies the elements for which this returns false
}
};
std::remove_copy_if(v_OrderInfo.cbegin(), v_OrderInfo.cend(), std::back_inserter(ret), pred(which_side));
Do note however that remove_if/remove_copy_if doesn't actually remove anything, just shifts the "removed" elements to the back of the vector. If you want to remove the elements as well use vector::erase on the return value of remove_copy_if.
Related
In my project there is a vector
std::vector<std::shared_ptr<MovingEntity>>gameObjects;
Which I want to delete elements from if they meet the criteria.
Method to delete elements:
void GameWorld::catchBees()
{
auto q = std::remove_if(bees.begin(), bees.end(), beeToClose);
bees.erase(q);
}
Method beeToClose:
bool GameWorld::beeToClose( const MovingEntity & bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
if (bee.getConstPosition().distanceTo(m_beekeeper->getPosition()) > keeper->getCatchDistance())
{
return true;
}
return false;
}
When I try to compile the code I get some errors which I tried to understand:
'GameWorld::beeToClose': non-standard syntax; use '&' to create a
pointer
Not sure why this message is given
'std::remove_if': no matching overloaded function found
I did not declare beeToClose right?
'q': cannot be used before it is initialized SDLFramework
q is not initialized because:
std::remove_if(bees.begin(), bees.end(), beeToClose);
does not run correct?
How can I remove a std::shared_ptr correctly from a vector correctly when meeting some criteria?
The syntax for forming a pointer to member function is &ClassName::FunctionName. So you need &GameWorld::beeToClose for a pointer to the beeToClose member function. In your case, you should use a lambda from which you call that function
auto q = std::remove_if(bees.begin(), bees.end(),
[&](shared_ptr<MovingEntity> const& bee){ return beeToClose(bee); });
Also, you're using the wrong vector::erase overload, you want the one that erases a range of elements, not the one that erases a single element.
bees.erase(q, bees.end());
The vector contains std::shared_ptr<MovingEntity> elements, so beeToClose() needs to accept a const std::shared_ptr<MovingEntity> & parameter as input, not a const MovingEntity & parameter. Also, beeToClose() appears to be a non-static class method that accesses a non-static class member (m_beekeeper), so you can't just pass beeToClose() directly to std::remove_if() as it does not have access to the calling object's this pointer, but you can wrap it in a lambda to capture the this pointer.
Try this:
void GameWorld::catchBees()
{
auto q = std::remove_if(bees.begin(), bees.end(),
[this](const const std::shared_ptr<MovingEntity> &bee) {
return this->beeToClose(bee);
}
);
bees.erase(q, bees.end());
}
bool GameWorld::beeToClose(const std::shared_ptr<MovingEntity> &bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
return (bee->getConstPosition().distanceTo(m_beekeeper->getPosition()) > keeper->getCatchDistance());
}
You might also consider moving the distance calculation into Beekeeper instead:
bool GameWorld::beeToClose(const std::shared_ptr<MovingEntity> &bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
return !keeper->isInCatchDistance(bee);
}
bool Beekeeper::isInCatchDistance(const std::shared_ptr<MovingEntity> &bee)
{
return (bee->getConstPosition().distanceTo(getPosition()) <= getCatchDistance());
}
I am implementing a member function called CurrentUser. It will take a username as parameter and return the User instance object which matches the given username. Below is the code
User& UserDB::currentUser(string username){
// userlists is a instance member which is list of user objects
for(list<User>::iterator i = userlists.begin(); i != userlists.end(); ++i)
{
if(*i.getName().compare(username)==0){
return *i;
}
}
return null;
}
Not sure if it is the correct way to do so. Correct me if it is wrong. Thanks!
Update:
hey guys thanks for your advice, i figure out a way to do so by returning a User pointer. Here is the code.
User* UserDB::currentUser(string username){
for(list<User>::iterator i = userlists.begin(); i != userlists.end(); ++i)
{
if(i->getName().compare(username)==0){
return i;
}
}
return null;
}
there are a couple of ways to do this cleanly.
You can of course return a pointer, but that will be surprising to people as it is more normal to return a reference or an object. pointers present object consumers with a number of problems, e.g.:
what should I conclude if it's null?
should I delete it?
and so on.
Returning a reference to something or a something removes these ambiguities.
Having said that, references cannot be empty, so the function must return something. If it does not find the item it's looking for, it must indicate that to the caller. One way is an exception (i.e. it was logically incorrect to ask for that item). However, if the item not being there is a normal occurrence, then you don't want to force your consumers to handle exceptions - that's bad form too.
So the answer is to return an object that encapsulates an optional reference.
A good example of this is boost::optional<User&> but if you don't want to include boost it's fairly simple to roll your own:
struct optional_user
{
using element_type = User;
using reference_type = element_type&;
optional_user() : _p(nullptr) {}
optional_user(reference_type r)
: _p(std::addressof(r))
{}
bool valid() const { return bool(_p); }
// compares to true if the user is present, false otherwise
operator bool() const { return valid(); }
reference_type value() const {
assert(_p);
return *_p;
}
// can be used anywhere a User& is required
operator reference_type () const {
return value();
}
private:
element_type* _p = nullptr;
};
now your function becomes:
optional_user UserDB::currentUser(string username)
{
typedef list<User>::iterator Iter;
for(Iter i = userlists.begin(); i != userlists.end(); ++i)
{
if(i->getName().compare(username)==0)
{
return optional_user(*i);
}
}
// return an indicator that the user is not present
return optional_user();
}
and your call site becomes:
optional_user = users.currentUser("bob");
if (optional_user) {
do_something_with(optional_user /* .value() */);
}
If you want to specifically return a reference, the item you are referring to must have a lifetime after execution leaves the function.
There are several alternatives:
static local variable in function
using dynamic memory
variable declared outside function
Pass by non-const reference
Here is an example of #1:
const std::string& Get_Model_Name(void)
{
static const std::string model_name = "Accord";
return model_name;
}
Other alternatives are to return a variable by value (copy). This doesn't use references. A copy is returned.
For example:
std::string Get_Manufacturer_Name(void)
{
return std::string("Honda");
}
You may also consider passing by parameter and modifying the parameter:
void Get_Lunch_Special_Name(std::string& entree_name)
{
entree_name = std::string("Beef Wellington");
}
this is the first time I've done something like this so I'm a little uncertain how I need to do this. I have a very simple class which contains some simple values and some getters:
class Nucleotide{
private:
char Base;
int Position;
int Polymorphic;
public:
Nucleotide(char ch, int pos);
int getPos();
char getBase();
int getPoly();
};
This class is present in another class that contains a vector of them:
class NucleotideSequence{
private:
std::string Name;
std::vector<Nucleotide> Sequence;
public:
NucleotideSequence(std::string name, std::vector<Nucleotide> seq);
std::string getName();
Nucleotide getBase(int pos1);
};
I want the method of the second class called getBase to be able to take a integer - say 1, and return the first Nucleotide object in the vector. What I've written is below:
Nucleotide NucleotideSequence::getBase(int pos1)
{
for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++)
{
if(pos1 == (*i).getPos())
{
return i; // Return a pointer to the correct base.
}
}
}
I've got Nucleotide as the return type but I was wondering really how I should change this - since if I return nucleotide because of pass by value would it not just return a copy of the object at that place in the vector? So I'd rather return a pointer/reference. I'm using an iterator in the loop so should I just return a pointer with the value of the iterator? How do I do this? In the function I return i but should I be returning i&? I'm uncertain about the specifics - presumably if I'm returning a pointer my return type needs to be Nucleotide* or perhaps Nucleotide& since & means address of? I've thought this through and read Cpp tuts but I'm still slightly unsure of the right answer.
Thanks,
Ben.
You have to return the Nucleotide by reference:
Nucleotide & NucleotideSequence::getBase(int pos1)
{
for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++)
{
if(pos1 == (*i).getPos())
{
return *i; // Notice the *i instead of i
}
}
}
A reference works very similarly to pointer (allows you to pass the actual object, not its copy), but cannot be null and cannot point to non-existing object, so it's a lot safer than pointer.
Note though, that if you don't find the desired Nucleotide, you don't return anything, what generally is not a good idea. In this case using pointers may actually be a better idea:
Nucleotide * NucleotideSequence::getBase(int pos1)
{
for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++)
{
if(pos1 == (*i).getPos())
{
return &(*i);
}
}
return nullptr;
}
You don't return a pointer, you attempt to return the iterator. And the function is declared to return an instance and not a pointer. Also, if you don't find the Nucleotide you don't return anything at all leading to undefined behavior if you try to use the "returned" value.
You could change the function to return a pointer, or a reference, or just a by value (copying like it's declared like not.
You can also change so that the function takes the Nucleotide as an argument instead, and then return a boolean indicator if it was found or not.
bool NucleotideSequence::getBase(int pos1, Nucleotide& n)
{
for (...)
{
if (...)
{
n = *i;
return true;
}
}
return false; // Not found
}
As far as your question is concerned, returning a reference (&) as suggested by others is the solution.
In order to improve your code, I would as well suggest a change:
Either go for the operator[], or use the at() present in std::vector.
Thus, you can directly say:
return Sequence[pos1]; or return Sequence.at(pos1);
Your code will benefit from some use of references for efficiency's sake. The getBase method signature should look like this:
const Nucleotide& NucleotideSequence::getBase(int pos1)
The NucleotideSequence constructor signature should look like this:
NucleotideSequence(const std::string& name, const std::vector<Nucleotide>& seq);
And the getName method like this:
const std::string& getName();
(Although return value optimisation might make that less important.)
As for the contents of getBase, it might help understanding to break down the code into:
const Nucleotide* NucleotideSequence::getBase(int pos1)
{
for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); ++i)
{
Nucleotide& ref = *i; //Get a reference to the object this iterator points to
if(pos1 == ref.getPos()) //compare its base to the argument
{
return &ref; // Return a pointer to the correct object.
}
}
return NULL; //or null if we didn't find the object we wanted
}
I am trying to return content of std::pair which has int and string values.
What return type for function should I keep?
I tried with both int and char return type but gives error for both. I have given error below:
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
std::pair<int,std::string>client()
{
std::vector<std::string> most { "lion","tiger","kangaroo",
"donkey","lion","tiger",
"lion","donkey","tiger"
};
std::map<std::string, int> src;
for(auto x:most)
++src[x];
std::multimap<int,std::string,std::greater<int> > dst;
std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()),
[] (const std::pair<std::string,int> &p) {
return std::pair<int,std::string>(p.second, p.first);
}
);
std::multimap<int,std::string>::iterator it = dst.begin();
for(int count = 0;count<3 && it !=dst.end();++it,++count)
std::cout<<it->second<<":"<<it->first<<std::endl;
return *it;
}
int main()
{
std::multimap<int,std::string>::const_iterator rec;
rec= client(); // Error no match for ‘operator=’ in ‘rec = client()()’
std::multimap<int,std::string>::iterator it = rec.begin(); //error: ‘std::multimap<int, std::basic_string<char> >::const_iterator’ has no member named ‘begin’
for(int count = 0;count<3 && rec !=it.end();++it,++count) // error: has no member named 'end'
std::cout<<rec->second<<":"<<rec->first<<std::endl;
}
Just return the pair of int & std::string itself
as the multimap contains that as its element
std::pair<int,std::string> client(){
//...
}
If you want to return the map entry (i.e., both the key and value), then just use std::pair<int, std::string> as the return type, as other answers mentioned.
If you want to just return the key, return it->first (and use int as the return type). If you want to return just the value, return it->second (and use std::string as the return type).
If you want to return the a value from a std::map I would not explicitly use std::pair (though it is perfectly fine to do so). Personally I would use the std::map::value_type which represents the type of the values stored in the map (note: all containers have a type member called value_type that represents the type being stored).
std::multimap<int,std::string>::value_type client()
{
// STUFF
std::multimap<int,std::string>::iterator it = dst.begin();
// STUFF;
return *it; // Note: this is UB if it == dst.end()
}
The reason I would use value_type rather than std::pair is normally I would not use explicit types but would have created typedefs (so it looks like this).
typedef std::multimap<int,std::string> MapForX; // Modification to map here
// Will automatically roll threw all
// the following code as everything
// is defined in terms of `MapForX`
MapForX::value_type client()
{
// STUFF
MapForX::iterator it = dst.begin();
// STUFF;
return *it; // Note: this is UB if it == dst.end()
}
Now if I change the type of the MapForX. Then I only have to change one thing (the single typedef). If you return std::pair<int,std::string> then you have to make changes in two places (the typedef and the return value). Which to me is redundant change that can cause problems.
As a demo: If you return std::pair<int, std::string> your code looks like this:
typedef std::multimap<int,std::string> MapForX; // Modification to map here
// Will automatically roll threw MOST
// the following code.
// But notice this return type is not defined in terms of MapForX
// Thus if you change MapForX you will also need to change the return type.
// to match the correct type.
std::pair<int, std::string> client()
{
// STUFF
MapForX::iterator it = dst.begin();
// STUFF;
return *it; // Note: this is UB if it == dst.end()
}
That works perfectly well. But in the future you have to make some changes. And you change the type of the map too int => MySpecialType. Now in my second example (with the typedef) you only need to make one change (in MapForX). In the example above you need to make two changes (one for MapForX and one std::pair on the return type).
#Martin York: You have good intentions but have you checked them against reality? Because value_type is exported as std::pair<const key_type, mapped_type>:
https://en.cppreference.com/w/cpp/container/map
This may work if you return a copy of a pair from an iterator. It won't work if you construct that pair within the function and then try to fill it because first can't be modified.
When the goal is to avoid the k/v types twice:
using the_map_value_type = std::pair<the_map::key_type, the_map::mapped_type>
Then use this type as a function result. Of course, only until the negligence has been eliminated in the STL with an export like detached_value_type.
Im trying to overload the [] operator in c++ so that I can assign / get values from my data structure like a dictionary is used in c#:
Array["myString"] = etc.
Is this possible in c++?
I attempted to overload the operator but it doesnt seem to work,
Record& MyDictionary::operator[] (string& _Key)
{
for (int i = 0; i < used; ++i)
{
if (Records[i].Key == _Key)
{
return Records[i];
}
}
}
Thanks.
Your code is on the right track - you've got the right function signature - but your logic is a bit flawed. In particular, suppose that you go through this loop without finding the key you're looking for:
for (int i = 0; i < used; ++i)
{
if (Records[i].Key == _Key)
{
return Records[i];
}
}
If this happens, your function doesn't return a value, which leads to undefined behavior. Since it's returning a reference, this is probably going to cause a nasty crash the second that you try using the reference.
To fix this, you'll need to add some behavior to ensure that you don't fall off of the end of the function. One option would be to add the key to the table, then to return a reference to that new table entry. This is the behavior of the STL std::map class's operator[] function. Another would be to throw an exception saying that the key wasn't there, which does have the drawback of being a bit counterintuitive.
On a totally unrelated note, I should point out that technically speaking, you should not name the parameter to this function _Key. The C++ standard says that any identifier name that starts with two underscores (i.e. __myFunction), or a single underscore followed by a capital letter (as in your _Key example) is reserved by the implementation for whatever purposes they might deem necessary. They could #define the identifier to something nonsensical, or have it map to some compiler intrinsic. This could potentially cause your program to stop compiling if you move from one platform to another. To fix this, either make the K lower-case (_key), or remove the underscore entirely (Key).
Hope this helps!
On a related note, one of the problems with operator[](const Key& key) is that, as templatetypedef states, in order to return a reference it needs to be non-const.
To have a const accessor, you need a method that can return a fail case value. In STL this is done through using find() and the use of iterators and having end() indicate a fail.
An alternative is to return a pointer, with a null indicating a fail. This is probably justified where the default constructed Record is meaningless. This can be also be done with the array operator:
Record* MyDictionary::operator[] (const string& keyToFind) const
{
for (int i = 0; i < used; ++i)
{
if (Records[i].Key == keyToFind)
{
return &Records[i];
}
}
return 0;
}
There is certainly a view that operator[] should return a reference. In that case, you'd most likely implement find() as well and implement operator[] in terms of it.
To implement find() you need to define an iterator type. The convenient type will depend in implementation. For example, if Records[] is a plain old array:
typedef Record* iterator;
typedef const Record* const_iterator;
const_iterator MyDictionary::end()const
{
return Records + used;
}
const_iterator MyDictionary::begin() const
{
return Records;
}
const_iterator MyDictionary::find(const string& keyToFind) const
{
for (iterator it = begin(); it != end(); ++it)
{
if (it->Key == keyToFind)
{
return it;
}
}
return end();
}