I have a class, how can i add one object of this class to map, and find it by id?
Class code:
class Client {
int FileDescriptor, Id, cryptcode;
unsigned char CustomData[256];
void PrepareClient()
{
// init code
}
public:
AnticheatClient (int fd, int id, int crypt_code)
{
FileDescriptor = fd;
Id = id;
cryptcode = crypt_code;
PrepareCrypt();
}
void OwnCryptEncrypt(unsigned char* data, int len)
{
//...
}
void OwnCryptDecrypt(unsigned char* data, int len)
{
//...
}
};
std::map<int, Client> ClientTable;
int main()
{
int id = 1;
Client c(1, id, 1);
// how can i add this client to map and how can i find it by id?
}
I tried so many example codes but not with custom class so they didn't work.
Thanks!
For adding a Client with key=10:
ClientTable[10] = Client(1, id, 1);
For find an element with key=10:
std::map<int, Client>::iterator it = ClientTable.find(10);
if (it != ClientTable.end()) {
int key = it->first;
Client c = it->second;
}
You can also use:
Client c = ClientTable[10];
but calling operator[] is not const. So, that is most probably not what you want to use if you just want to find an element.
1) "how can i add one object of this class to map?"
ClientTable[id] = c;
Well, technically, it adds a copy of the object to the map.
2) "and find it by id?"
Client lookerUpper = ClientTable[id];
Related
I am having trouble passing an array of object pointers from main() to a function from different class.
I created an array of object pointers listPin main() and I want to modify the array with a function editProduct in class Manager such as adding new or edit object.
Furthermore, I want to pass the whole listP array instead of listP[index]. How to achieve this or is there any better way? Sorry, I am very new to c++.
#include <iostream>
using namespace std;
class Product
{
protected:
string id, name;
float price;
public:
Product()
{
id = "";
name = "";
price = 0;
}
Product(string _id, string _name, float _price)
{
id = _id;
name = _name;
price = _price;
}
};
class Manager
{
protected:
string id, pass;
public:
Manager(string _id, string _pass)
{
id = _id;
pass = _pass;
}
string getId() const { return id; }
string getPass() const { return pass; }
void editProduct(/*array of listP*/ )
{
//i can edit array of listP here without copying
}
};
int main()
{
int numProduct = 5;
int numManager = 2;
Product* listP[numProduct];
Manager* listM[numManager] = { new Manager("1","alex"), new Manager("2", "Felix") };
bool exist = false;
int index = 0;
for (int i = 0; i < numProduct; i++) { //initialize to default value
listP[i] = new Product();
}
string ID, PASS;
cin >> ID;
cin >> PASS;
for (int i = 0; i < numManager; i++)
{
if (listM[i]->getId() == ID && listM[i]->getPass() == PASS) {
exist = true;
index = i;
}
}
if (exist == true)
listM[index]->editProduct(/*array of listP */);
return 0;
}
Since the listP is a pointer to an array of Product, you have the following two option to pass it to the function.
The editProduct can be changed to accept the pointer to an array of size N, where N is the size of the passed pointer to the array, which is known at compile time:
template<std::size_t N>
void editProduct(Product* (&listP)[N])
{
// Now the listP can be edited, here without copying
}
or it must accept a pointer to an object, so that it can refer the array
void editProduct(Product** listP)
{
// find the array size for iterating through the elements
}
In above both cases, you will call the function as
listM[index]->editProduct(listP);
That been said, your code has a few issues.
First, the array sizes numProduct and numManager must be compiled time constants, so that you don't end up creating a non-standard variable length array.
Memory leak at the end of main as you have not deleted what you have newed.
Also be aware Why is "using namespace std;" considered bad practice?
You could have simply used std::array, or std::vector depending on where the object should be allocated in memory. By which, you would have avoided all these issues of memory leak as well as pointer syntaxes.
For example, using std::vector, you could do simply
#include <vector>
// in Manager class
void editProduct(std::vector<Product>& listP)
{
// listP.size() for size of the array.
// pass by reference and edit the listP!
}
in main()
// 5 Product objects, and initialize to default value
std::vector<Product> listP(5);
std::vector<Manager> listM{ {"1","alex"}, {"2", "Felix"} };
// ... other codes
for (const Manager& mgr : listM)
{
if (mgr.getId() == ID && mgr.getPass() == PASS)
{
// ... code
}
}
if (exist == true) {
listM[index]->editProduct(listP);
}
You cannot have arrays as parameters in C++, you can only have pointers. Since your array is an array of pointers you can use a double pointer to access the array.
void editProduct(Product** listP){
and
listM[index]->editProduct(listP);
Of course none of these arrays of pointers are necessary. You could simplify your code a lot if you just used regular arrays.
Product listP[numProduct];
Manager listM[numManager] = { Manager("1","alex"), Manager("2", "Felix")};
...
for(int i = 0; i < numManager; i++ ){
if(listM[i].getId() == ID && listM[i].getPass() == PASS) {
exist = true;
index = i;
}
}
if(exist == true){
listM[index].editProduct(listP);
}
I am adding the header file and cpp file (it has main fucntion).
AuctionPrices.h
#ifndef AuctionPrices_h
#define AuctionPrices_h
/*
*
* class AuctionPrices - maintains Buy Order, Sell Order books
*/
#include <bits/stdc++.h>
#include <map>
//#pragma pack(1)
struct Order
{
char * itemId;
char * auctionId;
int Side;
};
class AuctionPrices
{
public:
virtual int AddNewOrder(char *itemId, char *auctionId, int Side, int Price) = 0;
virtual int DeleteOrder(char *itemId, char *auctionId) = 0;
virtual int Print() = 0;
};
class AuctionPrice_Imp : public AuctionPrices
{
public:
AuctionPrice_Imp();
~AuctionPrice_Imp();
std::map <int, Order, std::greater< int >> BuyMap;
std::map <int, Order, std::less< int >> SellMap;
int AddNewOrder(char *itemId, char *auctionId, int Side, int Price);
int DeleteOrder(char *itemId, char *auctionId);
int Print();
};
#endif
AuctionPrices_Imp.cpp
/**
* Auction Price Class implementation
* Constructor, AddNewOrder, DeleteOrder, Print
*
*/
#include <bits/stdc++.h>
#include <map>
#include "AuctionPrices.h"
using namespace std;
AuctionPrice_Imp::AuctionPrice_Imp()
{
}
AuctionPrice_Imp::~AuctionPrice_Imp()
{
}
int AuctionPrice_Imp::AddNewOrder(char *itemId, char *auctionId, int Side, int Price)
{
Order order;
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
order.Side = Side;
if (Side == 1)
{
BuyMap.insert (std::pair<int,Order>(Price,order));
//buyLevels_.insert( std::pair< OfPrice, Level< OrderEntry > >( price, buyLevel ) );
}
else if (Side == 2)
{
SellMap.insert (std::pair<int,Order>(Price,order));
}
else
{
return 0;
}
return 1;
}
int AuctionPrice_Imp::DeleteOrder(char *itemId, char *auctionId)
{
return 0;
}
int AuctionPrice_Imp::Print()
{
std::map <int,Order,std::greater< int >>::iterator buy_it;
std::map <int,Order,std::less< int >>::iterator sell_it;
// Print Sell Map
for ( sell_it = SellMap.begin();sell_it != SellMap.end(); sell_it++)
{
std::cout << sell_it->first << '\t' << std::endl;
}
// Print Buy Map
for ( buy_it = BuyMap.begin();buy_it != BuyMap.end(); buy_it++)
{
std::cout << buy_it->first << '\t' << std::endl;
}
return 1;
}
int main()
{
AuctionPrice_Imp * auctionPrice_Imp = new AuctionPrice_Imp();
/*
AddNewOrder(“item1”, “auction1”, 1, 100)
AddNewOrder(“item1”, “auction2”, 1, 101)
AddNewOrder(“item2”, “order3”, 1, 99)
AddNewOrder(“item2”, “order4”, 2, 100)
*/
auctionPrice_Imp->AddNewOrder("item1", "auction1", 1, 100);
auctionPrice_Imp->AddNewOrder("item1", "auction2", 1, 101);
auctionPrice_Imp->AddNewOrder("item2", "order3", 1, 99);
auctionPrice_Imp->AddNewOrder("item2", "order4", 2, 100);
auctionPrice_Imp->Print();
}
When I am running the code its giving segmentation fault at the line:
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Please anyone can help or correct the code.
The functions I am calling are supposed to add the orders to the Maps: BuyMap and SellMap. Once they have added to those map, I am using a print function to print the values.
Order order;
This creates a new Order object. Order does not have a constructor, so none of its class members, itemId, and auctionId, get initialized to point to anything. These pointers are uninitialized, random garbage. Immediately afterwards:
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Since neither itemId, nor auctionId, point to sufficient memory that are at least strlen(itemId)+1 or strlen(auctionId)+1 in size, respectively, this results in undefined behavior, and your crash.
In C++, before using a pointer, it is your responsibility to make sure that the pointer is valid, and points to the correct object, objects, or sufficiently-sized memory buffers. C++ will not do that for you, you have to do all that work yourself.
But if your intent is to write modern C++ code, it is much simpler just to use C++ classes, like std::strings instead of plain char * pointers. std::strings automatically handle all these low-level details, manage memory properly, without making it your responsibility to do so. You will find a complete description of std::string and many examples of using it in your C++ textbook.
You should use std::string to avoid having to deal with low level issues of pointers and memory allocation. These are the issues that you are getting wrong in your code. Here's your code rewritten to use std::string
struct Order
{
std::string itemId;
std::string auctionId;
int Side;
};
int AuctionPrice_Imp::AddNewOrder(std::string itemId, std::string auctionId, int Side, int Price)
{
Order order;
order.itemId = itemId;
order.auctionId = auctionId;
order.Side = Side;
See how easy that is? The code to use std::string is no different to the code that handles int.
I have to build a dynamic sql query. To proper execute it I have to do it in 3 steps:
Prepare statement
Bind Parameters with functions: bindString(string value, int index); bindInt(int value, int index);
Execute it
Because of the fact, that this query is build dynamically I have to store somewhere proper values for given index.
For example:
SELECT * FROM Table WHERE A = ? AND E = '?';
SELECT * FROM Table WHERE A = ? AND B = ? AND E = '?';
During building query I have to store somewhere that:
In the first case:
index 0 is for int A,
index 1 is for string E
In the second case:
index 0 is for int A
index 1 is for int B
index 2 is for string E
My best idea is to create two maps: < int, string >, < int, int > and during creating query set in first place indexes and in second place values and then creating two loops, one for strings, the second one for integers and binding parameters in them and it works fine.
However I wonder if is it possible to do everything in one loop using succeeding indexes and in type safety way.
Thank You.
I would consider creating a class to wrap SQL parameters.
In fact I would create an abstract class like that :
SQLParameterBase
{
std::string toString() = 0;
void print()
{
std::cout << toString();
}
}
And then a template class :
template<class ParamType>
SQLParameter : public SQLParameterBase
{
private:
ParamType value;
public:
std::string toString()
{
// You can use std::ostringstream to convert to string,
// or create another class (derivated from SQLParameterBase) with very specific values
}
}
And you could use it like that :
SQLParameterBase * params[10];
maps[0] = new SQLParameter<int>();
Hope that will help
Actually it is modified AMDG solution. Thanks to him!
class SQLParam {
public:
virtual ~SqlParam(){}
void bind(DatabaseHandler &db, int index) = 0;
};
class SQLParamInt {
private:
int value;
public:
SqlParamInt(int p_value) : value(p_value) {
}
~SqlParamInt() {}
int bind(DatabaseHandler &db, int index) {
return db.bindInt(value, index);
}
};
class SQLParamString {
private:
string value;
public:
SqlParamString(std::string p_value) : value(p_value) {
}
~SqlParamString() {}
int bind(DatabaseHandler &db, int index) {
return db.bindString(value, index);
}
};
typedef std::vector<std::unique_ptr<SqlParam>> SqlParamsContainer;
typedef std::unique_ptr<SqlParamInt> SqlParamIntPtr;
typedef std::unique_ptr<SqlParamString> SqlParamStringPtr;
In my function, building query:
int buildQuery(RequestHandler &request) {
SqlParamsContainer params;
stringstream query << "SELECT * FROM Table WHERE A = ?";
params.push_back(SqlParamIntPtr(new SqlParamInt(request.A())));
if(request.has_B()) {
params.push_back(SqlParamIntPtr(new SqlParamInt(request.B())));
query << " AND B = ?";
}
if(request.has_C()) {
params.push_back(SqlParamStringPtr(new SqlParamString(request.C())));
query << " AND C = ?";
}
query << ";";
db.prepare(query.str());
for(int i = 0; i < v_container.size(); i++)
v_container.at(i)->bind(db,i);
}
There is Boost::Any while it is more general than what you ask for and does not prevent the user from storing unsupported types you do not need to worry about creating the according subclasses.
If you want to return results as well from your DB Boost::Any might be the answer as well.
I suggest limiting the types in your bind function rather than in the storage. If you work with a variadic bind function this is necessary anyways.
I'm making a program for enciphering and deciphering text phrases that utilizes a 2D table. I have a single class that holds everything necessary for the cipher. However, I'm running into trouble when dealing with the table. I've got it constructed okay enough, but I'm having trouble encapsulating it in the class. I feel like it should be constructed automatically when an object is created, but right now I'm having to call it in through the main.
#include <iostream>
#include <string>
using namespace std;
class Cipher {
public:
Cipher();
Cipher(string key);
Cipher(string key, string message);
void buildTable(char table[][26]);
void newKey(string keyphrase);
void inputMessage();
string encipher(string message);
string decipher(string message);
string getPlainText() const;
string getCipherText() const;
private:
string key;
string plaintext;
string ciphertext;
};
.
.
.
.
void Cipher::buildTable(char table[][26]) {
char alphabet[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o', 'p','q','r','s','t','u','v','w','x','y','z'};
int alphaIndex = 0;
for (int index1 = 0; index1 < 26; index1++) {
for (int index2 = 0; index2 < 26; index2++) {
if ((index1 + index2) < 26) {
alphaIndex = index1 + index2;
table[index1][index2] = alphabet[alphaIndex];
}
else
alphaIndex = 0;
while (((index1 + index2) > 25) && index2 < 26) {
table[index1][index2] = alphabet[alphaIndex];
index2++;
alphaIndex++;
}
}
}
}
This table is key to the program functioning, and there is no reason for it to be changed. I tried including it as a private member, but ran into a lot of trouble. Should I be including this in the constructors, or what is the proper way to encapsulate this?
The "char table[][26]" that you have, I recommend to make it a private member of your class. And when in the constructor you should initialize it. Your "buildTable" member function should not take the array as a parameter, but instead it should initialize your private 2 dimensional array. By looking at your code, I don't see any reason as to why you should have your table on the stack of "buildTable" function.
This looks like a job for an Initialize On First Use function.
class Cipher {
public:
// ...
private:
using table_type = char[26][26];
// Or for C++03 mode,
// typedef char table_type[26][26];
static void buildTable(table_type& table);
static const table_type& getTable();
// ...
}
const Cipher::table_type& Cipher::getTable() {
static table_type the_table;
if (the_table[0][0] == '\0')
buildTable(the_table);
return the_table;
}
I prefer to leave the constructor parameters to feed-in the minimum class configuration values. So I would leave it as a private member. As for the values, I don't see why to re calculate them every time an instance is created, if they won't change, you just need to calculate them once and hard code them into the cpp file.
The *.h file:
class Cipher {
...
private:
...
static const int table[26][26];
};
The *.cpp file:
...
const int Cipher::table[26][26] = { ... };
...
My program reads user's input and create easy "table". User on the start specifies data types of columns and the number of rows.
User's input:
create table
add attribute string Name
add attribute int Age
rows 3
I need prepare a structure from user's input now. I have something like this:
CTable
{
unsigned attributesCnt;
string * attributesNames;
void ** attributes;
};
So, from the user's input, the progam does these steps:
CTable myTable;
myTable.attributesCnt = 2; // string "Name", int "Age"
myTable.attributesNames = new string[2];
myTable.attributesNames[0] = "Name";
myTable.attributesNames[1] = "Age";
attributes = new void[2]; // 2 attributes
attributes[0] = (void*) new string[3]; // there will be 3 rows
attributes[1] = (void*) new int[3];
I need remember that "attributes[0]" is string and "attributes[1]" is int too.
Is this "right" way?
I would like use only standard libraries.
What you are looking for is a tagged union also called a variant. It allows you to store multiple data types at the same location just like a regular union but includes an additional but separate data member that indicates it's type. The C++ Standard Library does not include variants but they are easy enough to implement.
Once you have a variant you can apply it to your example like below.
myTable.attributesNames[0] = "Name";
myTable.attributesNames[1] = "Age";
// I recommend using std::vector here instead of using new/delete yourself
attributes = new Variant*[2]; // 2 attributes
attributes[0] = new Variant("player name");
attributes[1] = new Variant(player_age);
The following example shows how the variant might be implemented.
struct Variant
{
enum Type
{
INT,
STRINGPTR
};
Type type_;
union
{
int int_;
const char* stringptr_;
} data_;
explicit Variant(int data) : type_(INT)
{
data_.int_ = data;
}
explicit Variant(const char *data) : type_(STRINGPTR)
{
data_.stringptr_ = data;
}
Type getType() const { return type_; }
int getIntValue() const
{
if(type_ != INT)
throw std::runtime_error("Variant is not an int");
return data_.int_;
}
const char *getStringPtr() const
{
if(type_ != STRINGPTR)
throw std::runtime_error("Variane is not a string");
return data_.stringptr_;
}
};
int main()
{
Variant intval(1);
Variant stringval("hello");
std::cout << intval.getIntValue() << std::endl;
std::cout << stringval.getStringPtr() << std::endl;
}