STL list iteration issue - c++

I am working with an STL list and keep getting errors while attempting to retrieve the last element. I have a class
class Buffer {
private:
list<Flit*> fifo;
...
public:
...
Flit *peek_last_flit(void) const;
...
};
and the implementation
Flit *Buffer::peek_last_flit(void) const {
if (fifo.empty())
return 0;
Flit *f = *(fifo.begin());
return f;
}
I have a similar implementation that returns the head of the list.
Flit *Buffer::peek_flit(void) const {
if (fifo.empty())
return 0;
Flit *f = *(fifo.begin());
return f;
}
How may I approach this issue(I am calling both procedures but when I call Peek_last_flit I get a debug asserion failure message:
Expression: list iterator not dereferencable.
How can I preserve iterators?
Any help would be much appreciated.

Flit *Buffer::peek_last_flit(void) const {
if (fifo.empty())
return 0;
return fifo.back();
}

container.end() is never dereferencable.
You need --container.end() to get the last element.

Related

How to properly handle if a function exits without encoutering a return

I have a function that search a vector and returns the item if it is found. But I want to know that best software appraoch to handle if it is not found.
I have created a function and could return -1 or something but that wouldn't match the return type.
koalaGraph::PVertex Koala::lookUpVertexbyName(const std::string&vertexName, const std::vector<koalaGraph::PVertex>& koalaVertices) {
for (size_t i = 0; i < koalaVertices.size(); i++) {
if(koalaVertices[i]->info.name == vertexName)
return koalaVertices[i];
}
}
If a situation is encountered where the item being searched for is not in the vector then program will exit.
You can use std::optional
#include <optional>
std::optional<koalaGraph::PVertex>
Koala::lookUpVertexbyName(const std::string&vertexName,
const std::vector<koalaGraph::PVertex>& koalaVertices) {
for (size_t i = 0; i < koalaVertices.size(); i++) {
if(koalaVertices[i]->info.name == vertexName)
return koalaVertices[i];
}
return {};
}
int main()
{
Koala k;
//...
auto maybeVertex = k.lookUpVertexByName("foo",vertices);
if(maybeVertex)
koalaGraph::PVertex&& vertex = *maybeVertex;
//alternatively
if(maybeVertex.has_value())
//found
}
You could use a for-loop and return a iterator.
std::vector<koalaGraph::PVertex>::const_iterator
Koala::lookUpVertexbyName(
const std::string&vertexName,
const std::vector<koalaGraph::PVertex>& koalaVertices)
{
for(auto iter = koalaVertices.begin(); iter != koalaVertices.end(); ++iter) {
if(koalaVertices[i]->info.name == vertexName) {
return iter;
}
}
return koalaVertices.end();
}
Further you check if you got end back. end indicates if the value was found or not.
auto iter = <fucntioncall> // lookUpVertexbyName
if (iter == <vector>.end() {
// abort or do what ever you want
}
To use the value you have to dereference the iterator. DON'T derefence the end-iterator, it will lead you to neverland -> undefined behavior.
std::string test = *iter;
Why not use std::find_if instead of reinventing the wheel. See this link.
struct equal
{
equal(const std::string& vertexName) : vertexName_(vertexName) { }
bool operator()(const koalaGraph::PVertex& pVertex) const
{
return pVertex->info.name == vertexName_;
}
private:
std::string vertexName_;
};
And then:
std::find_if(koalaVertices.begin(), koalaVertices.end(), eq(vertexName));
Regarding handling the errors in function as it has already been stated there are multiple approaches that one can take. Returning an iterator instead of object(you will avoid copying this way too) is one of them. end() iterator would then indicate that the name was not found.
There are three ways to exit a function:
Return a value
Throw a value
Call std::abort or std::exit (possibly indirectly)
(std::longjmp which you shouldn't use)
If you don't do any of the above, then behaviour will be undefined. If you don't want to do 1., then your options are 2. or 3. Abort and exit will terminate the process. A throw can be caught, but an uncaught throw will cause std::abort.
Note that just because you don't find a value, it's not necessarily impossible to return some value. What you can do is return a "sentinel" value that represents "not found". For example, std::string functions that return an index will return std::string::npos when there is no result. Functions returning a pointer might return null, and functions returning an iterator would return an iterator the the end of the range.
If there is no representation of your return type that could be reserved for a sentinel, there is a way to add such representation by wrapping the return type with additional state. The standard library has a generic wrapper for this: std::optional.
Another wrapper is the proposed std::expected (it's not accepted to the standard as far as I know, but there are plenty of non-standard implementations). It allows storing information about the reason for not returning a proper value which similar to what you can do with exceptions.
P.S. Your function appears to be nearly identical to std::find_if. Use standard algorithms when possible. Also consider a data structure that is more efficient for searching if the search space is large.

Custom iterator out of bounds

I have an iterator class. Let's call it PIterator here. A MessageBuffer is iterated and is being outputted correctly, unless the nSizeOfMessage plus where the iterator currently points to is equal to the size of the whole message (position correct, index one too large).
If I check for the last element and decrement by one, it should work. Though it seems to be a "wrong way" to me. Yeah, I am not quite sure on this, so my problem is shown in this code snippet, maybe someone knows a good solution, tried to figure it out for quite a while.
Yes, I do know how to use a debugger, I know where the problem lies and it is explained just fine. I do not know how to fix this, unless used the way I mentioned.
This compiles fine under Visual Studio 2015.
Please also see the comments in the main function.
#include <iostream>
#include <vector>
class MessageBuffer
{
public:
MessageBuffer(const std::string &s)
{
_msgBuffer.assign(s.begin(), s.end());
}
char &operator[](std::size_t nIndex)
{
return _msgBuffer[nIndex];
}
//more functions...
private:
std::vector<char> _msgBuffer;
};
class PIterator
{
public:
PIterator(MessageBuffer &b)
: m_Ref(b)
, m_Where(0)
{ }
PIterator &operator=(PIterator &other)
{
if (this == &other)
return *this;
this->m_Ref = other.m_Ref;
this->m_Where = other.m_Where;
return *this;
}
//more functions...
PIterator operator+(unsigned int nValue) const
{
PIterator copy(*this);
copy.m_Where += nValue;
return copy;
}
PIterator &operator+=(unsigned int nValue)
{
m_Where += nValue;
return *this;
}
char &operator*()
{
return m_Ref[m_Where];
}
private:
MessageBuffer &m_Ref;
std::size_t m_Where;
};
int wmain(int argv, wchar_t **args)
{
std::string msg = "123MyMessage"; //Length 12
// ^ Index 3, Position 4
MessageBuffer mb(msg);
PIterator itr(mb);
//Calculations - here the results hardcoded
std::size_t nSizeOfMessage = 9; //The size of the message without the numbers
//itr.m_Where is 3 - That's where the non-numeric part of the message starts
itr += 3;
std::string needThis;
PIterator cpy = itr + nSizeOfMessage; //itr points to the first element of the message
//cpy is now out of bounds - position is correct, but index is 1 too large
needThis.assign(&*itr, &*cpy); //boom
return 0;
}
Instead of
needThis.assign(&*itr, &*cpy);
you need to use
needThis.assign(itr, cpy);
This will work if your PIterator satisfies iterator requirements.
The way you call assign, you pass pointers instead of iterators, which is valid by itself. But, to get the pointers, you dereference the iterators first. Dereferencing past-the-end iterator is undefined behavior, which is caught in Debug configuration of the compiler.
The solution I came up with was quite simple.
Instead of having a temporary iterator, I'll be using the char pointer and increment it's address by the size of the message, thus receiving always the correct last element. Should've seen that earlier.
needThis.assign(&*itr, (&*itr) + nSizeOfMessage);

How to return an object reference from a function in C++ and how to call the function from the client side?

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");
}

Modifying elements in a STL List - C++

I am attempting to construct a binary search tree using a generalized list in C++.
class Element
{
private:
list<Element*> _children;
char* _name;
// and other data members/methods...
}
As you can see, I have a class "Element" and it has a list "_children" of Element pointers.
I am trying to access these children so that I may add children to them and so forth...
However, I cannot modify these values with my current method of using a "const_iterator" and my reason for doing that is that the "begin()" method of _children returns a const_iterator.
Someone help? Thank you :)
UPDATE: Thank you all so much... It turns out, I mistakenly had a method return a const reference of the _children data member.
const list<Element*>& getChildren();// return [_children]
I just deleted const and it works perfect now. Thank you! :D
The begin function will return a const_iterator if the list is const. So for the _children list you should be able to just get the standard iterator to let you perform non-const operations on it:
list<Element*>::iterator it = _children.begin();
This however won't work if your passing off a const reference to the list and then trying to get the non-const iterator from that. Something like this would not be allowed:
void doSomething( const list<Element*>& l )
{
list<Element*>::iterator it = l.begin();
}
You would need to instead pass a non-const reference to the list.
The other case where this would be not allowed is in a const function, i.e.
void doSomething() const
{
list<Element*>::iterator it = _children.begin();
}
But would need to see more of your code to confirm if you're doing this or not.
If you want to use _children as an array, how about trying std::vector class instead of std::list?
Here's usage.
#include <iostream>
#include <vector>
int main(void) {
std::vector<int> list;
list.push_back(1);
list.push_back(2);
list.push_back(3);
for (int i = 0; i < list.capacity();++i){
std::cout << list[i] << std::endl;
}
return 0;
}

Separating vector of objects

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.