This is a snippet of an open source code. Full source code is available https://github.com/gec/dnp3/blob/master/src/opendnp3/DNP3/ResponseContext.h
ObjectWriteIterator owi = arAPDU.WriteContiguous(apObject, start,stop);
for(size_t i = start; i <= stop; ++i) {
if(owi.IsEnd()) { // out of space in the fragment
this->mStaticWriteMap[arKey] =
boost::bind(&ResponseContext::WriteStaticObjects<T>, this, apObject,
arStart, arStop, arKey, _1); return false;
}
apObject->Write(*owi, arStart->mValue);
++arStart; //increment the iterators
++owi;
}
ObjectWriteIterator::ObjectWriteIterator() :
mpPos(NULL),
mIndex(1),
mStart(0),
mStop(0),
mObjectSize(0)
{}
My question is: I don't understand is where *owi is referring in this context.
owi is an iterator, which is a 'standard' C++ interface for iterating over some collection.
The interface has them use pointer-symantics, so the * operator 'dereferences' the iterator and returns a reference to the value it currently 'points' to, and incrementing it via ++ moves it to the next item in the collection being iterated over.
In this case, it looks like a collection of ObjectWrite objects inside the collection specified by apObject between start and stop (start and stop are also typically defined by iterators set to some location in the collection).
sorry, I was earlier not sure about one can build a self contained 'Mock up' iterator class which use hidden is the header file
inline boost::uint8_t* ObjectWriteIterator::operator*() const
{
if(this->IsEnd()) throw InvalidStateException(LOCATION, "End of
iteration");
return mpPos;
}
in the header file. Sorry for wild goose run. Thanks for the prompt reply and I learned something new about the the core implementation of the iterator as well.
Related
CppCheck suggest me to replace one of my code by a STL algorithm, I'm not against it, but I don't know how to replace it. I'm pretty sure this is a bad suggestion (There is warning about experimental functionalities in CppCheck).
Here is the code :
/* Cutted beginning of the function ... */
for ( const auto & program : m_programs )
{
if ( program->compare(vertexShader, tesselationControlShader, tesselationEvaluationShader, geometryShader, fragmentShader) )
{
TraceInfo(Classname, "A program has been found matching every shaders.");
return program;
}
}
return nullptr;
} /* End of the function */
And near the if condition I got : "Consider using std::find_if algorithm instead of a raw loop."
I tried to use it, but I can't get the return working anymore... Should I ignore this suggestion ?
I suppose you may need to use that finding function not once. So, according to DRY, you need to separate the block where you invoke an std::find_if algorithm to a distinct wrapper function.
{
// ... function beginning
auto found = std::find_if(m_programs.cbegin(), m_programs.cend(),
[&](const auto& prog)
{
bool b = prog->compare(...);
if (b)
TraceInfo(...);
return b;
});
if (found == m_programs.cend())
return nullptr;
return *found;
}
The suggestion is good. An STL algorithm migth be able to choose an appropriate
approach based on your container type.
Furthermore, I suggest you to use a self-balancing container like an std::set.
// I don't know what kind of a pointer you use.
using pProgType = std::shared_pointer<ProgType>;
bool compare_progs(const pProgType &a, const pProgType &b)
{
return std::less(*a, *b);
}
std::set<std::shared_pointer<prog_type>,
std::integral_constant<decltype(&compare_progs), &compare_progs>> progs.
This is a sorted container, so you will spend less time for searching a program by a value, given you implement a compare operator (which is invoked by std::less).
If you can use an stl function, use it. This way you will not have to remember what you invented, because stl is properly documented and safe to use.
I'm trying to determine why the following code is throwing a segfault on line 10 (where we dereference upgradeIter).
bool UpgradeType::isAffected(const UnitType *unitType) const{
if(std::find(effects.begin(), effects.end(), unitType)!=effects.end()) return true;
// Check if the unit has any of the affected tags
std::set<string>::iterator upgradeIter;
for(upgradeIter = tags.begin(); upgradeIter != tags.end(); ++upgradeIter) {
std::set<string>::iterator unitIter;
for(unitIter = unitType->getTags().begin(); unitIter != unitType->getTags().end(); ++unitIter) {
string unitTag = *unitIter;
string upgradeTag = *upgradeIter;
if(unitTag == upgradeTag) return true;
}
}
return false;
}
The context is that UpgradeType has "tags" (just a set of strings). Units also have tags. If a unit shares at least one tag with the upgrade, then the unit is affected by the upgrade.
I don't see any reason why the mentioned line would crash. It seems to me that there is no circumstances under which the iterator could be invalid.
In other parts of the code that display the contents of tags (used in very similar ways), the output is as expected.
EDIT: I've just found out that unitType->getTags().size() is 0. So I don't understand why the body of the for loop is even executed. unitIter != unitType->getTags().end(), however, is evaluating to true. This seems off.
I managed to find a solution to this with the help of Yggdrasil on this site (which also means that Matt McNabb in the question's comments was correct). Quoting his post below:
As someone more or less mentioned on stackoverflow: Change getTags() to return a reference, not a value/copy.
const set &getTags() const {return tags;}
Be aware that the return type is const, so use a const iterator.
Not sure if that's all, but you don't want a (deep) copy there, for sure. The iterator gets out of bounds because you check against the end of a different set. Every call to getTags() gets its own copy.
Can anyone tell me why my list iterator hates .end()-1 ? I want to iterato to one before the list end, I was under the impression you could always do this !
Code on request
std::list<Hammer::shared_ptr<Hammer::Actor>> collisionActorsList;
std::list<Hammer::shared_ptr<Hammer::Actor>>::iterator _actorUpdateIter = collisionActorsList.begin();
while(_actorUpdateIter != (collisionActorsList.end()-1)) // ERROR HERE
{
// check against every other actor
std::list<Hammer::shared_ptr<Hammer::Actor>>::iterator _otherActorsUpdateIter = _actorUpdateIter+1; // ERROR HERE TOO
while(_otherActorsUpdateIter != collisionActorsList.end())
{// SOME STUFF }
}
std::list uses a bidirectional iterator, which doesn't support operator- or operator+. Use std::prev(collisionActorsList.end()) and std::next(_actorUpdateIter).
As pointed out below in the comments, you should be aware of whether your list is empty. If it is, these will fail to do what you want. There's a simple function for that: collisionActorsList.empty().
I'm currently learning C++ and practicing my Knowledge by implementing an simple AddressBook Application. I started with an Entry class and an AddressBook class which implements a STL Map to access the entries by the last names of the persons. Now I arrived at the following code:
Entry AddressBook::get_by_last_name(string last_name){
if(this->addr_map.count(last_name) != 0){
//What can I do here?
} else {
return addr_map[last_name];
}
In Scripting Languages I would just return something like -1, Error Message(A List in Python) to indicate that the Function failed. I don't want throw an exception, because it's part of the application logic. The Calling Class should be able to react to the request by printing something on the console or opening a Message Box. Now I thought about implementing the Scripting Languae Approach in C++ by introducing some kind of an Invalid State to the Class Entry. But isn't that bad practice in C++? Could it be that my whole class design is just not appropriate? I appreciate any help. Please keep in mind that I'm still learning C++.
Some quick notes about your code:
if(this->addr_map.count(last_name) != 0){
//What can I do here?
You probably wanted it the other way:
if(this->addr_map.count(last_name) == 0){
//handle error
But your real problem lies here:
return addr_map[last_name];
Two things to note here:
The operator[] for map can do 2 things: If the element exists, it returns it; If the element doesn't exist, it creaets a new (key,value) pair with the specified key and value's default constructor. Probably not what you wanted. However, if your if statement from before would have been the right way, then the latter would never happen because we would knowthe key exists before hand.
In calling count() before, you effectively tell map to try and find the element. By calling operator[], you are telling map to find it again. So, you're doing twice the work to retrieve a single value.
A better (faster) way to do this involves iterators, and the find method:
YourMap::iterator it = addr_map.find(last_name); //find the element (once)
if (it == addr_map.end()) //element not found
{
//handle error
}
return *it.second; //return element
Now, back to the problem at hand. What to do if last_name is not found?
As other answers noted:
Simplest solution would be to return a pointer (NULL if not found)
Use boost::optional.
Simply return the YourMap::iterator but it seems that you are trying to "hide" the map from the user of AddressBook so that's probably a bad idea.
throw an exception. But wait, now you'll have to first check that calling this method is 'safe' (or handle the exception when appropriate). This check requires a boolean method like lastNameExists which would have to be called before calling get_by_last_name. Of course then we'er back to square 1. We're performing 2 find operations to retrieve a single value. It's safe, but if you're doing A LOT of calls to get_by_last_name then this is potentially a good place to optimize with a different solution (besides, arguably the exception is not very constructive: What's wrong with searching for something that isn't there, huh?).
Create a dummy member for Entryindicating that is not a real Entry but that is very poor design (unmanageable, counter intuitive, wasteful - you name it).
As you can see, the first 2 solutions are by far preferable.
One dead-simple option is to change the return type to Entry* (or const Entry*) and then return either the address of the Entry if found, or NULL if not.
If you use Boost, you could return a boost::optional<Entry>, in which case your success code would be the same, but on not-found you'd say return boost::none. This is fancier, but does about the same thing as using a pointer return type.
Throwing an exception is definitely the 'correct' C++ thing to do, based on your function return type.
You might want a function like this to help you, though:
bool AddressBook::lastNameExists(const string &last_name)
{
return addr_map.count(last_name) > 0;
}
Note that your current code returns the entry 'by value' so modifying the returned entry won't update the map. Not sure if this is by accident or design...
Other answers have given various approaches, most of them valid. I didn't see this one yet:
You could add a second parameter with a default value:
Entry AddressBook::get_by_last_name(string last_name, const Entry& default_value){
if(this->addr_map.count(last_name) == 0){
return default_value;
} else {
return addr_map[last_name];
}
In this particular instance, there might not be a sensible default value for a non-existing last name, but in many situations there is.
In C++ you have several ways of signalling that an issue happened in your function.
You can return a special value which the calling code will recognize as an invalid value. This can be a NULL pointer if the function should return a pointer, or a negative value if your function returns an index in an array, or, in the case of a custom class (e.g. your Entry class) you can define a special Entry::invalid value or something similar that can be detected by the calling function.
Your calling code could look like
if ( entryInstance->get_by_last_name("foobar") != Entry::invalid)
{
// here goes the code for the case where the name is valid
} else {
// here goes the code for the case where the name is invalid
}
On the other hand you can use the C++ exceptions mechanism and make your function throw an exception. For this youcan create your own exception class (or use one defined in the standard library, deriving from std::exception). Your function will throw the exception and your calling code will have to catch it with a try...catch statement.
try
{
entryInstance->get_by_last_name("foobar")
}
catch (Exception e)
{
// here goes the code for the case where the name is invalid
}
// here goes the code for the case where the name is valid
Apart from the fact that you could have more than one entry per surname.
Eliminate the getter, and you've solved the problem, or at least shifted it elsewhere.
Tell the AddressBook to display people with given surnames. If there aren't any it can do nothing.
AddressBookRenderer renderer;
AddressBook contacts;
contacts.renderSurnames("smith", renderer);
contacts.renderCompletions("sm", renderer);
//etc
You can do what std::map (and the other containers do).
You return an iterator from your search function.
If the search does not find a value that is useful return an iterator to end().
class AddressBook
{
typedef <Your Container Type> Container;
public:
typedef Container::iterator iterator;
iterator get_by_last_name(std::string const& lastName) {return addr_map.find[lastName];}
iterator end() {return addr_map.end();}
};
Your address book is a container like object.
Not finding an item in a search is likely to happen but it does not have enough context to incorporate error handling code (As the address book could be used from lots of places and each place would have different error handling ideas).
So you must move the test for not found state out of your address book.
just like "Python" we return a marker. In C++ this is usually an iterator to end() which the calling code can check and take the appropriate action.
AddressBook& ab = getAddressBookRef();
AddressBook::iterator find = ab.get_by_last_name("cpp_hobbyist");
if (find != ab.end())
{
Entity& person *find; // Here you have a reference to your entity.
// you can now manipulate as you want.
}
else
{
// Display appropriate error message
}
I am using a QList and I want to iterator though it, but the iterator that i get from it keeps failing, even if I use the auto keyword or not.
for( auto iter = myModel->getList().begin(); iter != myModel->getList().end(); ++iter )
{
if( (*iter)->getList().empty() )
{
if( (*iter)->getData()->getCode() == baseData->getCode() )
return true;
}
}
return false;
Does anyone know why this could be happening? Or is there a different way that I am to use the QList::iterator?
EIDT:
I have noticed another odd thing about this. I do see that the iterator is showing (error)0, and this is odd because it actually contains the data I need.
But if I edit my code to look like this:
QList<T*> tempList = myModel->getList();
for( auto iter = tempList .begin(); iter != tempList .end(); ++iter )
{
if( (*iter)->getList().empty() )
{
if( (*iter)->getData()->getCode() == baseData->getCode() )
return true;
}
}
return false;
then everything works fine. I guess it is a solution, but does anyone know why it needs to be done like this? Or am I just not seeing something very important?
I see two issues with the code.
a) myModel->getList() returns a copy of your QList declared something like this:
QList<T*> YourModel::getList()
you actually should get an access violation. But I don't know if that's what happening.
b) If you only rely on what Visual Studio is saying about iter, forget it, its wrong. It just can't handle the iterator. Allthough the iterator says its (error)0 as an int it will still give you the correct data if dereferenced.
If none of the above is the case please specify what actually goes wrong, is the for loop beeing skipped all together? If so, I'll edit my answer accordingly.
Best regards
D
EDIT
The reason why it works fine with the temporary List object is following:
The moment you create an iterator with the begin() method of the list, the list detaches its private data (implicit sharing), meaning it creates a deep copy of itself because you could change the data with that iterator. Without the temporary object myModel->getList() creates a temporary object which immediately after the iterator has been created is beeing destroyed. From that moment on the iterator points to nowhere. You might try using the const iterator, this one should work without detaching the private data hence without the problem.
Another approach would be to make your model return the list as a const reference or a pointer.
Another way would be to discard iterators and use the at() method of the list directly. Makes code more readable in my opinion.
What type does myModel->getList return?
Unless you have a list of lists this line looks suspect:
if( (*iter)->getList().empty() )
Anyways, the calls themselves overall look good. The only real explanation is either dependent on your types, or the data (or lack thereof) There is no clear and evident problem in the code you posted.