How to access member elements of a std::queue data structure? [duplicate] - c++

This question already has answers here:
Compilation Error: void value not ignored as it ought to be in std::queue::pop() [duplicate]
(2 answers)
Invalid use of void expression with a Queue and .pop()
(2 answers)
Why doesn't std::queue::pop return value.?
(6 answers)
Closed 2 years ago.
Coding in C+, using Visual Studio 2019, I have a structure defined. I am creating a queue of that data structure and have pushed 2 elements into the queue. Now the question is how to access the members of the structure elements inside the queue?? Any guidance is appreciated!
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <queue>
typedef struct _myqueuestruct
{
string name;
int citypin;
int employeeId;
}myqueuestruct;
int main()
{
queue<myqueuestruct> myQ;
myqueuestruct myQelement;
myQelement.name = "Harry";
myQelement.citypin = "Ohio";
myQelement.employeeId = "345";
// Insert some elements into the queue
myQ.push(myQelement);
myQelement.name = "John";
myQelement.citypin = "Jaipur";
myQelement.employeeId = "223";
// Insert some elements into the queue
myQ.push(evtSvcElement);
//myQ.size();
//queue<myqueuestruct>::iterator it = myQ.begin();
for (int i = 0; i < myQ.size(); i++)
{
cout << myQ.front();
myQ.pop(); //???? How do I access the member values of the elements of the queue?
}
while (1);
return 0;
}

Well, front returns a reference to the first element, so like this:
std::cout << myQ.front().name; // and similarly for other elements
Or, for example, make a referenence yourself:
auto& ref = myQ.front();
ref.name = "foo";
ref.citypin = 42;
// etc.

I have modified your code to get it compiling and working: (Note: I have used C++17 standard using g++ to compile this code but it should work for visual studio 2019
#include <iostream>
#include <queue>
typedef struct _myqueuestruct
{
std::string name;
std::string citypin;
int employeeId;
}myqueuestruct;
int main()
{
std::queue<myqueuestruct> myQ;
myqueuestruct myQelement;
myQelement.name = "Harry";
myQelement.citypin = "Ohio";
myQelement.employeeId = 345;
// Insert some elements into the queue
myQ.push(myQelement);
myQelement.name = "John";
myQelement.citypin = "Jaipur";
myQelement.employeeId = 223;
// Insert some elements into the queue
myQ.push(myQelement);
while (myQ.size() > 0)
{
auto & e = myQ.front();
std::cout << "Name: " << e.name
<< " CityPin: " << e.citypin
<< " EmployeeId: " << e.employeeId << std::endl;
myQ.pop();
}
return 0;
}
I would like to point out a few changes I have to make in your above code:
in your struct definition you used int datatype but you assigned char string to the same. I have modified the datatype to be std::string.
using while loop for iterating through all the elements and using myQ.size() every time instead of using for loop.
std::cout - holding the element reference in a local variable inside the loop and printing all member variables.
Improvements you can make to above code:
There are multiple transient copies of the object being created when you push the object into the queue. I would suggest refer std::queue documentation here: http://www.cplusplus.com/reference/queue/queue/ and try to enhance above code with
emplace_back
overload operator<< for your class for printing class members, this would help you learn about operator overloading.

Related

This simple code should work but I am getting warning [duplicate]

This question already has answers here:
Code outside functions
(3 answers)
Closed 2 years ago.
#include <iostream>
using namespace std;
int *i = new int;
*i = 0;
int &j = *i;
j++;
//cout << *i << endl;
I have a code like that, and I know this syntax is true but it gives warning in Visual Studio Code like this:
quiz2_q8.cpp:5:4: error: expected constructor, destructor, or type conversion before '=' token
*i = 0;
^
quiz2_q8.cpp:7:1: error: 'j' does not name a type
j++;
Am I missing a library to include? I thought iostream is enough for this quiz code.
You can't have arbitrary statements in the global namespace. You need to put it into a function, e.g. like this:
int main() {
int *i = new int;
*i = 0;
int &j = *i;
j++;
}
Most programs have a starting point, which is the main method/function/procedure whatever you want to call it. Each function has a scope given by { // fun scope }. A good tutorial series on C++ might come to your aid, or perhaps a book. With that said here's a template for such a program.
#include <iostream>
using namespace std;
int main(){
return 0;
}
Statements for being executed must be inside functions.
#include <iostream>
using namespace std;
int main(void) { // add this
int *i = new int;
*i = 0;
int &j = *i;
j++;
//cout << *i << endl;
} // add this

C++ std::list with struct containing list with struct

I'm new to C++ (I did C before but never C++) I believe I have syntax problem.
I want to sort some orders by price level into a list.
So my list has positions with inside:
the price level
another std::list with all orders at that price. (Orders)
An Order is a struct with:
userid
quantity
So I ended with :
#include<iostream>
#include<list>
using namespace std;
typedef struct Order {
int userid;
int qty;
} Order;
typedef struct Bid {
int price;
list<Order> Orders;
} Bid;
typedef list<Bid> bids;
int main(void)
{
bids list;
Order order_to_insert;
list.begin();
list.front().price = 13000;
order_to_insert.userid = 3;
order_to_insert.qty = 20;
list.front().Orders.begin();
list.front().Orders.front().userid =3;
list.front().Orders.front().qty = 20;
// list.front().Orders.front() = order_to_insert; // compiles even if i uncomment this.
cout << "Liste : " << list.front().price << endl;
cout << list.front().Orders.front().qty << endl;
return 0;
}
The most intuitive way initially was to use the commented line, it compiles but gives seg fault.
I commented to assign values to fields directly and it seg fault also.
What is the proper way to do that?
First of all this line list.begin(); and that line list.front().Orders.begin(); don't do anything. Remove them.
Now the main problem. Elements in lists don't appear automagically. Lists are empty when created. Have a look at this line:
list.front().price = 13000;
At that point your list is empty, there is no .front(). So its an undefined behaviour, probably the cause of the segfault.
This will do:
Bid bid;
list.push_back(bid);
list.front().price = 13000;
// or if C++11
list.emplace_back();
list.front().price = 13000;
The same goes for list.front().Orders.front() and every other line using .front().
Side note: You may want to use list.emplace_back instead of push_back. Also you may want to use std::vector instead of std::list. There are several performance advantages over a list and it should be used by default unless you really know that you need lists.
Calling front() on an empty list has undefined behavior. An empty list doesn't have a first item, so you shouldn't be trying to access it.
You can use push_back() eg. to add an item into the list, which you can then access and modify.
list.push_back(Bid());
You do not insert elements into your list. std::list::front will return the first element of the list if it is non-empty, but behaviour is undefined if the list is empty.
std::list::begin returns an iterator to the first element, if the list is non-empty or the past-the-end iterator if the list is empty.
Use std::list::push_back to insert new elements into your list.
Thanks guys for clear explanations and advises.
I ended with the following working code :
#include <iostream>
#include <list>
using namespace std
typedef struct Order {
int userid;
int qty;
} Order;
typedef struct Bid {
int price;
list<Order> Orders;
} Bid;
typedef list<Bid> bids;
int main(void)
{
Bid bid;
bids bidList;
Order order_to_insert;
bidList.push_back(bid);
bidList.front().price =13000;
order_to_insert.userid = 3;
order_to_insert.qty = 20;
bidList.front().Orders.push_back(order_to_insert);
bidList.front().Orders.front() = order_to_insert;
cout << "Liste : " << bidList.front().price << endl;
cout << bidList.front().Orders.front().move << endl;
return 0;
}

Getting "vector subscript out of range" error

I'm currently trying to get "variadic functions" down and just trying to load 4 names in a string vector and then print them out. When I do this with 'int' type and use numbers, it works fine, but when I use a string vector I get the error.
#include "stdafx.h"
#include<cstdio>
#include<cstdarg>
#include<string>
#include<vector>
#include<iostream>
using namespace std;
int count;
vector<string> namesVector;
void names(int count, ...)
{
va_list namesList;
int i; // for loop
va_start(namesList, count);
for (i = 0; i < count; i++)
{
string currentElement;
currentElement = va_arg(namesList, string);
namesVector[i] = currentElement;
}
va_end(namesList);
}
int main()
{
int nameCount = 4;
names(nameCount,"jon", "maggie", "joan", "alfred");
for (int i = 0; i < nameCount; i++)
{
cout << "Name at element " << i << " is: " << namesVector[i] << endl;
}
}
C++ only allows to use trivially-copyable types as variadic arguments. As std::string is constructible from a char* pointer which points to a null-terminated buffer, you may use char* instead of std::string type. Just replace
currentElement = va_arg(namesList, string);
with
currentElement = va_arg(namesList, char*);
in your code. To get rid of this limitation, consider variadic templates, which generate code in compile-time for any type you use.
Your code also contains a run-time error. This:
namesVector[i] = currentElement;
is very likely to crash your program as you didn't allocate any memory in the vector. Vectors are actually dynamic arrays, so you should either pass a size argument to appropriate constructor, or call resize on the vector. In you case you may do neither of it, but just use push_back method:
namesVector.push_back(currentElement);

C++ pass array of struct by value [duplicate]

This question already has answers here:
Does C++ pass objects by value or reference?
(5 answers)
Closed 8 years ago.
I'm having trouble understanding why passing my array, containing elements, to
a function, results in my array no longer containing elements within the function.
Before passing in an array containing 3 objects from my items sturct, the size of
the array is 72 (24 for each object). Once inside the function, the size of my array
is 24, which I assumed to be the size of the first element in my array. However, this
is not the case.
My question, why isn't my array the same in the function as it is outside of the function?
Header File:
#include <iostream>
using namespace std;
// header file for shop items
struct items
{
string name;
int price;
string examine;
};
main file:
#include "shop_items.h"
#include <iostream>
using namespace std;
int getLongestName(items &shop)
{
/*Iterates over each element in array
if int longest < length of element's name, longest = length of element's name.*/
int longest = 0;
// shop size is 24, the size of a single element.
cout << "sizeof(shop) right inside of function:" << sizeof(shop) << endl;
return longest;
}
void test1()
{
// initialize shop items
items sword;
items bow;
items shield;
// set the name, price, and examine variables for each item.
sword.name = "sword"; sword.price = 200; sword.examine = "A sharp blade.";
bow.name = "bow"; bow.price = 50; bow.examine = "A sturdy bow.";
shield.name = "sheild"; shield.price = 100; shield.examine = "A hefty shield.";
// create an array for iterating over the each element in item shop.
items shop[] = {sword, bow, shield};
//sizeOfShop = 72, 24 for each element (the sword, bow and shield).
cout << "sizeof(shop) right outside function: " << sizeof(shop) << endl;
int longest = getLongestName(*shop);
}
int main()
{
test1();
cout << "\n\nPress the enter key to exit." << endl;
cin.get();
}
What is useful about a reference-to-array parameter?
The answer to the above question has helped me a lot at better understanding what it is that I'm trying to do. However, I'm running into different errors when attempting to pass my array by reference as well.
You do not pass the array. You pass only the first element of the array.
int longest = getLongestName(*shop);
Expression *shop is equivalent to shop[0] So inside the function you get the size of one object of type items.
Moreover you declared function getLongestName as having parameter of type reference to an object of type items.
int getLongestName(items &shop);
If you wanted to pass the whole array by reference to the function then you should declare it as
int getLongestName( items ( &shop )[3] );
and the function has to be called as
int longest = getLongestName(shop);
Or as
int getLongestName(items *shop, size_t n);
where the second parameter specifies the number of elements in the array.
And the function has to be called as
int longest = getLongestName(shop, 3 );

Segmentation Fault when trying to push a string to the back of a list

I am trying to write a logger class for my C++ calculator, but I'm experiencing a problem while trying to push a string into a list.
I have tried researching this issue and have found some information on this, but nothing that seems to help with my problem. I am using a rather basic C++ compiler, with little debugging utilities and I've not used C++ in quite some time (even then it was only a small amount).
My code:
#ifndef _LOGGER_H_
#define _LOGGER_H_
#include <iostream>
#include <list>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::list;
using std::string;
class Logger
{
private:
list<string> mEntries;
public:
Logger() {}
~Logger() {}
// Public Methods
void WriteEntry(const string& entry)
{
mEntries.push_back(entry);
}
void DisplayEntries()
{
cout << endl << "**********************" << endl
<< "* Logger Entries *" << endl
<< "**********************" << endl
<< endl;
for(list<string>::iterator it = mEntries.begin();
it != mEntries.end(); it++)
{
// *** BELOW LINE IS MARKED WITH THE ERROR ***
cout << *it << endl;
}
}
};
#endif
I am calling the WriteEntry method by simply passing in a string, like so:
mLogger->WriteEntry("Testing");
Any advice on this would be greatly appreciated.
* CODE ABOVE HAS BEEN ALTERED TO HOW IT IS NOW *
Now, the line:
cout << *it << endl;
causes the same error. I'm assuming this has something to do with how I am trying to get the string value from the iterator.
The code I am using to call it is in my main.cpp file:
#include <iostream>
#include <string>
#include <sstream>
#include "CommandParser.h"
#include "CommandManager.h"
#include "Exceptions.h"
#include "Logger.h"
using std::string;
using std::stringstream;
using std::cout;
using std::cin;
using std::endl;
#define MSG_QUIT 2384321
#define SHOW_LOGGER true
void RegisterCommands(void);
void UnregisterCommands(void);
int ApplicationLoop(void);
void CheckForLoggingOutput(void);
void ShowDebugLog(void);
// Operations
double Operation_Add(double* params);
double Operation_Subtract(double* params);
double Operation_Multiply(double* params);
double Operation_Divide(double* params);
// Variable
CommandManager *mCommandManager;
CommandParser *mCommandParser;
Logger *mLogger;
int main(int argc, const char **argv)
{
mLogger->WriteEntry("Registering commands...\0");
// Make sure we register all commands first
RegisterCommands();
mLogger->WriteEntry("Command registration complete.\0");
// Check the input to see if we're using the program standalone,
// or not
if(argc == 0)
{
mLogger->WriteEntry("Starting application message pump...\0");
// Full version
int result;
do
{
result = ApplicationLoop();
} while(result != MSG_QUIT);
}
else
{
mLogger->WriteEntry("Starting standalone application...\0");
// Standalone - single use
// Join the args into a string
stringstream joinedStrings(argv[0]);
for(int i = 1; i < argc; i++)
{
joinedStrings << argv[i];
}
mLogger->WriteEntry("Parsing argument '" + joinedStrings.str() + "'...\0");
// Parse the string
mCommandParser->Parse(joinedStrings.str());
// Get the command names from the parser
list<string> commandNames = mCommandParser->GetCommandNames();
// Check that all of the commands have been registered
for(list<string>::iterator it = commandNames.begin();
it != commandNames.end(); it++)
{
mLogger->WriteEntry("Checking command '" + *it + "' is registered...\0");
if(!mCommandManager->IsCommandRegistered(*it))
{
// TODO: Throw exception
mLogger->WriteEntry("Command '" + *it + "' has not been registered.\0");
}
}
// Get each command from the parser and use it's values
// to invoke the relevant command from the manager
double results[commandNames.size()];
int currentResultIndex = 0;
for(list<string>::iterator name_iterator = commandNames.begin();
name_iterator != commandNames.end(); name_iterator++)
{
string paramString = mCommandParser->GetCommandValue(*name_iterator);
list<string> paramStringArray = StringHelper::Split(paramString, ' ');
double params[paramStringArray.size()];
int index = 0;
for(list<string>::iterator param_iterator = paramStringArray.begin();
param_iterator != paramStringArray.end(); param_iterator++)
{
// Parse the current string to a double value
params[index++] = atof(param_iterator->c_str());
}
mLogger->WriteEntry("Invoking command '" + *name_iterator + "'...\0");
results[currentResultIndex++] =
mCommandManager->InvokeCommand(*name_iterator, params);
}
// Output all results
for(int i = 0; i < commandNames.size(); i++)
{
cout << "Result[" << i << "]: " << results[i] << endl;
}
}
mLogger->WriteEntry("Unregistering commands...\0");
// Make sure we clear up our resources
UnregisterCommands();
mLogger->WriteEntry("Command unregistration complete.\0");
if(SHOW_LOGGER)
{
CheckForLoggingOutput();
}
system("PAUSE");
return 0;
}
void RegisterCommands()
{
mCommandManager = new CommandManager();
mCommandParser = new CommandParser();
mLogger = new Logger();
// Known commands
mCommandManager->RegisterCommand("add", &Operation_Add);
mCommandManager->RegisterCommand("sub", &Operation_Subtract);
mCommandManager->RegisterCommand("mul", &Operation_Multiply);
mCommandManager->RegisterCommand("div", &Operation_Divide);
}
void UnregisterCommands()
{
// Unregister each command
mCommandManager->UnregisterCommand("add");
mCommandManager->UnregisterCommand("sub");
mCommandManager->UnregisterCommand("mul");
mCommandManager->UnregisterCommand("div");
// Delete the logger pointer
delete mLogger;
// Delete the command manager pointer
delete mCommandManager;
// Delete the command parser pointer
delete mCommandParser;
}
int ApplicationLoop()
{
return MSG_QUIT;
}
void CheckForLoggingOutput()
{
char answer = 'n';
cout << endl << "Do you wish to view the debug log? [y/n]: ";
cin >> answer;
switch(answer)
{
case 'y':
ShowDebugLog();
break;
}
}
void ShowDebugLog()
{
mLogger->DisplayEntries();
}
// Operation Definitions
double Operation_Add(double* values)
{
double accumulator = 0.0;
// Iterate over all values and accumulate them
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator += values[i];
}
// Return the result of the calculation
return accumulator;
}
double Operation_Subtract(double* values)
{
double accumulator = 0.0;
// Iterate over all values and negativel accumulate them
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator -= values[i];
}
// Return the result of the calculation
return accumulator;
}
double Operation_Multiply(double* values)
{
double accumulator = 0.0;
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator *= values[i];
}
// Return the value of the calculation
return accumulator;
}
double Operation_Divide(double* values)
{
double accumulator = 0.0;
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator /= values[i];
}
// Return the result of the calculation
return accumulator;
}
Did you remember to call mLogger = new Logger at some point? Did you accidantally delete mLogger before writing to it?
Try running your program in valgrind to see whether it finds any memory errors.
After your edit, the solution seem clear:
Your first line in main() is :
mLogger->WriteEntry("Registering commands...\0");
Here mLogger is a pointer that has never been initialized. This is "undefined behaviour", meaning anything can appen, often bad things.
To fix this you can either make it a "normal" variable, not a pointer or create a Logger instance using new (either at the declaration or as the first line in main).
I suggest you to not use a pointer to be sure the logger is always there and is automatically destroyed.
By the way, it seems like you want to create every instance of objects on the heap using pointers. It's not recommanded if it's not necessary. You should use pointers ONLY if you want to explicitely state the creation (using new) and destruction (using delete) of the instance object. If you just need it in a specific scope, don't use a pointer. You might come from another language like Java or C# where all objects are referenced. If so, you should start learning C++ like a different language to avoid such kind of problem. You should learn about RAII and other C++ scpecific paradigm that you cannot learn in those languages. If you come from C you should too take it as a different language. That might help you avoid complex problems like the one you showed here. May I suggest you read some C++ pointer, references and RAII related questions on stackoverflow.
First, you don't need to create the std::list on the heap. You should just use it as a normal member of the class.
class Logger
{
private:
list<string> mEntries; // no need to use a pointer
public:
Logger() // initialization is automatic, no need to do anything
{
}
~Logger() // clearing and destruction is automatic too, no need to do anything
{
}
//...
};
Next, entryData don't exist in this code so I guess you wanted to use entry. If it's not a typo then you're not providing the definition of entryData that is certainly the source of your problem.
In fact I would have written your class that way instead:
class Logger
{
private:
list<string> mEntries;
public:
// no need for constructor and destructor, use the default ones
// Public Methods
void WriteEntry(const string& entry) // use a const reference to avoid unnecessary copy (even with optimization like NRVO)
{
mEntries.push_back( entry ); // here the list will create a node with a string inside, so this is exactly like calling the copy constructor
}
void DisplayEntries()
{
cout << endl << "**********************" << endl
<< "* Logger Entries *" << endl
<< "**********************" << endl
<< endl;
for(list<string>::iterator it = mEntries.begin();
it != mEntries.end(); ++it) // if you want to avoid unnecessary copies, use ++it instead of it++
{
cout << *it << endl;
}
}
};
What's certain is that your segfault is from usage outside of this class.
Is an instance of Logger being copied anywhere (either through a copy constructor or operator=)? Since you have mEntries as a pointer to a list, if you copy an instance of Logger, they will share the value of the pointer, and when one is destructed, it deletes the list. The original then has a dangling pointer. A quick check is to make the copy constructor and operator= private and not implemented:
private:
void operator=(const Logger &); // not implemented
Logger(const Logger &); // not implemented
When you recompile, the compiler will flag any copies of any Logger instances.
If you need to copy instances of Logger, the fix is to follow the Rule of 3:
http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
You can do this by eliminating the need for the destructor (by not using a pointer: list<string> mEntries), or by adding the needed code to the copy constructor and operator= to make a deep copy of the list.
You only need to do
list<string> entries;
entries.push_back();
You do not need to create a pointer to entries.
Nothing too obvious, though you typed
mEntries->push_back(string(entryData));
and I htink you meant entry instead of entryData. You also don't need the string conversion on that line, and your function should take entry by const reference.
However, none of these things would cause your program to segfault. What compiler are you using?
You're missing the copy constructor. If the Logger object is copied and the original deleted, you'll be dereferencing memory that was previously deleted.
A simplified example of the problem
Logger a;
{
Logger b;
a=b;
}
a.WriteEntry("Testing");
Add a copy constructor.
Logger(const Logger& item)
{
mEntries = new list<string>();
std::copy(item.mEntries->begin(), item.mEntries->end(), std::back_inserter(*mEntries));
}