NOTE: I am new to C++ and may do things that are bad practice and if you see that please tell me so I can fix that and please don't be mean. I have only started coding 1-2 months ago. And I am still learning. Please be open to the fact I may not know everything.
This is a console text-based game. It works great! Although, I am creating a feature in it to allow the user to drag and drop any amount of other databases on it to allow database transfers. Although this works fine the problem is that I have a little process it will do to try and make sure none of the info in the databases is the same by placing a number to them,
Example there will be 2 profiles 1 in each file. They are both named main. Then the user drags the second database onto the game and it loads that database into the original one. But now becuase there are 2 SIMILAR profile names it won't be able to differentiate which is which. So then it goes through a little function which scans the database and places a number in front of the copies. Starting at 5 and working its way up. Although this would seem to work and not be that hard to actually do I have hit a problem and I do not know what is wrong. I do know however it is something with how it scans for duplicates. Please help.
I have tried for like a whole day trying different methods or re-writing the code. Google has not revealed a lot to me.
I am using the following libraries in my code. (Some might not be used in the example but tbh I don't remember which is directly used in THIS function).
#include <iostream>
#include <iterator>
#include <cstring>
#include <cmath>
#include <cassert>
#include <string>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <utility>
#include <vector>
#include <array>
#include <functional>
#include <fstream>
Here is the scanning function to make sure there are no duplicate profiles.
Let me explain what happens.
I make a ton of variables which are used in the database. As you can see inside of the database it has a certain order.
Using file stream I access the database. (I have a function which will combine all the databases the user dragged in and the current profiles and data which works just fine).
The pattern in the database looks something like this.
profile_name user_name 100 3 0 0 0 0 knight 1 100 0 0
profile name health etc
If you look at the variables you will see the technical order.
void scanCopy()
{
std::string profile{ "John's_Profile" };
std::string name{ "John_Doe" };
int health{ 0 };
int damage{ 0 };
int gold{ 0 };
int exp{ 0 };
int level{ 0 };
int score{ 0 };
std::string CLASS{ "null" };
int dungeon{ 0 };
int maxHealth{ 0 };
int lives{ 0 };
int kills{ 0 };
std::ifstream in("data/database.txt");
std::vector <std::string> profiles;
int sizeOfVector{ 0 };
while (in >> profile >> name >> health >> damage >> gold >> exp >> level >> score >> CLASS >> dungeon >> maxHealth >> lives >> kills)
{
profiles.resize(sizeOfVector += 1);
profiles.at(sizeOfVector - 1) = { profile };
std::cout << profiles.at(sizeOfVector - 1) << "\n\n";
}
in.close();
for (int loop{ 0 }; loop < sizeOfVector; ++loop)
{
int compare{ loop };
for (int index{ loop }; index < sizeOfVector; ++index)
{
if (compare == index)//meaning they are like at profiles(1)and (1)
continue;
if (profiles.at(compare) == profiles.at(index))
{
std::ofstream out("data/~database.txt", std::ios::app);
in.open("data/database.txt");
int nameIndex{ 5 };
while (in >> profile >> name >> health >> damage >> gold >> exp >> level >> score >> CLASS >> dungeon >> maxHealth >> lives >> kills)
{
if (profile == profiles.at(index))
{
out << profile << nameIndex << " " << name << " " << health << " " << damage << " " << gold << " " << exp << " " << level << " " << score << " " << CLASS << " " << dungeon << " " << maxHealth << " " << lives << " " << kills << " " << std::endl; //Notice at the start profile is put into the database with an extra variable nameIndex to make its name now unique.
++nameIndex;
}
else
{
out << profile << " " << name << " " << health << " " << damage << " " << gold << " " << exp << " " << level << " " << score << " " << CLASS << " " << dungeon << " " << maxHealth << " " << lives << " " << kills << " " << std::endl;
}
}
}
}
}
in.close();
remove("data/database.txt");
in.open("data/~database.txt");
std::ofstream out("data/database.txt", std::ios::app);
//A buffer to copy everything inside a file to a string.
std::string upData((std::istreambuf_iterator<char>(in)),
(std::istreambuf_iterator<char>()));
/////
if (out)
out << upData; //putting everything in the tmp file to the file named database.txt
out.close();
in.close();
remove("data/~database.txt");
in.close();
out.close();
}
The problem is that it does not do its job. It will put numbers by anything. Besides that, it will also seem to overflow or something. What it does is after you already dragged something in, it pretends to work. Then any more input from dragging it does not get scanned. Thing is that everything is copied from the files the user drags from the database to a tmp file. Then the database is deleted and the temp file is renamed to database.txt. The problem is that this whole scan function seems to not be working right and I don't see the problem in it. Does anyone know a good way to do something like this or what the problem is? Thanks!
We really do not need the backstory that this is a game, that users can do XYZ and so on. Please construct a minimal example, as in minimal reproducible example. Often by constructing those, you yourself discover the problem. – Fureeish
Thank you Fureeish. I have found the problem. I was sending the function too many times which wiped the file or it did not scan it all the way. It is hard to explain the real thing I did because it was easy but I can't explain it well.
ALL IN ALL. I examined and found the bug, I was sending it to this function I posted up there too many times. or too little times.
In Doulos's SystemC Transfer Level Model documentation, it is written
The top-level module of the hierarchy instantiates one initiator and
one memory, and binds the initiator socket on the initiator to the
target socket on the target memory. The sockets encapsulate everything
you need for two-way communication between modules, including ports
and exports for both directions of communication. One initiator socket
is always bound to one target socket.
My understanding of this was that when you create an initiator and a target the initiator starts the communication by calling b_transport, thereby triggering the target, which can reply back. However, I have been writing some code and this does not seem to be the case. Let us look at an example.
I have a very basic implementation of an adder that can be talked to using transfer level modeling. This modules servers as the target.
adder.cc
#define SC_INCLUDE_DYNAMIC_PROCESS
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
#include <iostream>
using namespace sc_core;
using namespace std;
#include "adder.h"
adder::adder(sc_module_name name)
: sc_module(name), socket("socket2")
{
socket.register_b_transport(this, &adder::b_transport);
socket.register_transport_dbg(this, &adder::transport_dbg);
}
void adder::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay)
{
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 addr = trans.get_address();
uint32_t *ptr = (uint32_t*)trans.get_data_ptr();
unsigned int len = trans.get_data_length();
unsigned char *byt = trans.get_byte_enable_ptr();
unsigned int wid = trans.get_streaming_width();
addend1 = *ptr;
addend2 = *(++ptr);
add();
cout << "addend1: " << addend1 << endl;
cout << "addend2: " << addend2 << endl;
cout << "sum: " << sum << endl;
uint32_t *return_sum_loc = ptr;
for(int i = 0; i< 2; i++) {
return_sum_loc++;
}
memcpy(return_sum_loc, (char*) &sum, sizeof(uint32_t));
cout << "New sum for return: " << *(return_sum_loc) << endl;
}
unsigned int adder::transport_dbg(tlm::tlm_generic_payload& trans)
{
return 0;
}
void adder::add()
{
sum = addend1 + addend2;
}
Then I have a test_bench module that is going to serve as the initiator
test_bench.cc
#define SC_INCLUDE_DYNAMIC_PROCESS
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
using namespace sc_core;
using namespace std;
#include "test_bench.h"
#include <fstream>
#include <iostream>
test_bench::test_bench(sc_module_name name):
sc_module(name), socket("socket")
{
SC_THREAD(run_tests);
}
void test_bench::run_tests()
{
ifstream infile("./adder.golden.dat");
ofstream ofs;
ofs.open("./adder.dat");
uint32_t theoretical_sum = 0;
while(infile >> data[0] >> data[1] >> theoretical_sum)
{
tlm::tlm_generic_payload *trans = new tlm::tlm_generic_payload;
sc_time delay = sc_time(10, SC_NS);
cout << "Sending" << endl;
cout << "Data[0]: " << data[0] << endl;
cout << "Data[1]: " << data[1] << endl;
trans->set_data_ptr((unsigned char*)data);
socket->b_transport(*trans, delay);
cout << "data[2]" << data[2] << endl;
ofs << data[0] << "\t" << data[1] << "\t" << data[2] << "\n";
delete trans;
}
infile.close();
ofs.close();
printf ("Comparing against output data \n");
if (system("diff -w adder.dat adder.golden.dat"))
{
cout << "*******************************************" << endl;
cout << "FAIL: Output DOES NOT match the golden output" << endl;
cout << "*******************************************" << endl;
}
else
{
cout << "*******************************************" << endl;
cout << "PASS: The output matches the golden output!" << endl;
cout << "*******************************************" << endl;
}
}
Here is the parent module that instantiates and connects them.
main.cc
#include "systemc.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
#include "tlm_utils/tlm_quantumkeeper.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
#include "test_bench.h"
#include "adder.h"
SC_MODULE(Top)
{
test_bench *tb;
adder *ad;
sc_signal<bool> rst;
sc_signal<bool> tb_irq;
sc_signal<bool> ad_irq;
Top(sc_module_name name) :
rst("rst")
{
tb = new test_bench("test_bench");
ad = new adder("adder");
tb->socket.bind(ad->socket);
tb->irq(tb_irq);
ad->irq(ad_irq);
}
};
int sc_main(int argc, char *argv[])
{
Top *top = new Top("Top");
sc_start();
}
When I run the executable this is the output I get.
< 1 0 0
< 1 1 0
< 2 1 0
< 2 2 0
< 2 3 0
< 3 3 0
< 4 3 0
< 4 4 0
< 5 4 0
< 5 5 0
1 0 1
1 1 2
2 1 3
2 2 4
2 3 5
3 3 6
4 3 7
4 4 8
5 4 9
5 5 10
FAIL: Output DOES NOT match the golden output
So my original thought was that you were passing by value this payload into the b_transport function of an initiator that is bound to a target. The target will receive and decode this payload. This part is happening. I am able to parse the uint32_t s passed in by value to the data[]. What I eventually realized based on my 0 return values, that were written into the memory that was passed, is that this is not actually passed by value. For some reason it is created as a pointer type, then it is dereferenced when passed. This in essence destroys that target's ability to manipulate the memory that was passed to hand back a response to the initiator.
So this whole two-way communication thing Aynsley mentioned has me a little confused. By two-way does, he mean both modules need target and initiator sockets to enable two-way communication?
This is the signature of b_transport call:
void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay )
Payload is passed by reference, so target can modify it. Initiator can read returned value from the same payload object.
So this whole two-way communication thing Aynsley mentioned has me a
little confused. By two-way does, he mean both modules need target and
initiator sockets to enable two-way communication?
Blocking transport protocol implemented by b_transport call is unidirectional. Initiator module is active, target module is passive. Transaction finishes in a single call. Target is allowed to call wait() inside b_transport implementation.
But TLM2.0 also supports non-blocking protocol that consists of two calls:
nb_transport_fw from initiator to target
nb_transport_bw from target to initiator
This bidirectional protocol allows more fine-grained modeling of bus timing. For example you can model of out-of-order transaction processing in AMBA AXI bus.
In practice however almost everyone uses b_transport. Most models I've seen don't even support non-blocking interface.
As you can see in the main function I've created a group of threads that execute the exact same function yet with different parameters. The function simply prints out vector's values. Now the problem is that these threads interfere with one another. What I mean is that one thread does not finish printing (cout) before another starts, and it goes like sdkljasjdkljsad. I want some sort of chaotic order, such as, for example:
Thread 1 Vector[0]
Thread 2 Vector[0]
Thread 1 Vector[1]
Thread 3 Vector[0]
Thread 4 Vector[0]
Thread 2 Vector[1]
Rather than:
Thread 1 Thread 2 Vector[0] Vector[0]
Thread 2 Vector[1]
Thread 1 Thread 4 Vector[1] Thread 3 Vector[0] Vector[1]
How can I solve this problem? P.S. Data file is simply a list of player names, weight and bench-press per line. Transforming these to strings and placing in a vector (yeah, sounds dumb, but I'm just fulfilling a task).
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <string>
#include <thread>
#include <sstream>
#include <iomanip>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
using namespace std;
vector<string> Kategorijos;
vector< vector<string> > Zaidejai;
ifstream duom("duom.txt");
string precision(double a) {
ostringstream out;
out << setprecision(6) << a;
return out.str();
}
void read() {
string tempKat;
int tempZaidSk;
vector<string> tempZaid;
string vardas;
int svoris;
double pakeltasSvoris;
while (duom >> tempKat >> tempZaidSk) {
Kategorijos.push_back(tempKat);
for (int i = 0; i < tempZaidSk; i++) {
duom >> vardas >> svoris >> pakeltasSvoris;
tempZaid.push_back(vardas + " " + to_string(svoris) + " " + precision(pakeltasSvoris));
}
Zaidejai.push_back(tempZaid);
tempZaid.clear();
}
duom.close();
}
void writethreads(int a) {
int pNr = a+1;
for (int i = 0; i < (int)Zaidejai[a].size(); i++) {
cout << endl << "Proceso nr: " << pNr << " " << i << ": " << Zaidejai[a][i] ;
}
}
void print() {
for (int i = 0; i < (int)Kategorijos.size(); i++) {
cout << "*** " << Kategorijos[i] << " ***" << endl;
for (int j = 0; j < (int)Zaidejai[i].size(); j++) {
cout << j+1<<") "<< Zaidejai[i][j] << endl;
}
cout << endl;
}
cout << "-------------------------------------------------------------------" << endl;
}
int main()
{
read();
print();
boost::thread_group threads
;
for (int i = 0; i < (int)Kategorijos.size(); i++) {
threads.create_thread(boost::bind(writethreads, i));
}
threads.join_all();
system("pause");
return 0;
}
Welcome to the problem of thread synchronization! When only one thread can use a resource at a time, the lock you use to control that resource is a mutex. You can also store the data for one thread to output at the end, or you can have the threads synch up at a barrier.
You can synchronise them, the console writes, with an appropriate mutex. But in this case, with the console output, maybe don't use threads at all. Else send the printing to a dedicated thread that deals with it.
The alternative to using the usual cout overloaded operator << is to write the content to a local buffer or stringsteam (including the new line) and then, with a single function call, write that to the console. The single function call will assist in the console writer only writing one buffer's contents at a time.
I am writing a custom logger where I buffer my log messages in a std::stringstream and flush it to a file (std::ofstream) whenever the std::stringstream is big enough(to save some IO latency) . sincestd::stringstream doesn't have a .size() method, I use seekg and tellg :
template <typename T>
MyClass & operator<< (const T& val)
{
boost::unique_lock<boost::mutex> lock(mutexOutput);
output << val; //std::stringstream output;
output.seekg(0, std::ios::end);
if(output.tellg() > 1048576/*1MB*/){
flushLog();
}
return *this;
}
Problem:
It seems to me that, whenever I invoke this method, it uses seekg to start counting the bytes from the beginning all the way to the end and get the size using tellg. I came up with this design to save some IO time in the first place, but: isn't this continuous counting impose a larger cost(if the number of calls to this method is high and log messages are small as in most of the cases)?
is there a better way to do this?
And a side question: is 1MB a good number for buffer size in a normal nowadays computers?
Thank you
You can just use ostringstream::tellp() to get the length of the string. Here's an example lifted from http://en.cppreference.com/w/cpp/io/basic_ostream/tellp.
#include <iostream>
#include <sstream>
int main()
{
std::ostringstream s;
std::cout << s.tellp() << '\n';
s << 'h';
std::cout << s.tellp() << '\n';
s << "ello, world ";
std::cout << s.tellp() << '\n';
s << 3.14 << '\n';
std::cout << s.tellp() << '\n' << s.str();
}
Output:
0
1
13
18
hello, world 3.14
This question already has answers here:
How to concatenate a std::string and an int
(25 answers)
Closed 6 years ago.
int i = 4;
string text = "Player ";
cout << (text + i);
I'd like it to print Player 4.
The above is obviously wrong but it shows what I'm trying to do here. Is there an easy way to do this or do I have to start adding new includes?
With C++11, you can write:
#include <string> // to use std::string, std::to_string() and "+" operator acting on strings
int i = 4;
std::string text = "Player ";
text += std::to_string(i);
Well, if you use cout you can just write the integer directly to it, as in
std::cout << text << i;
The C++ way of converting all kinds of objects to strings is through string streams. If you don't have one handy, just create one.
#include <sstream>
std::ostringstream oss;
oss << text << i;
std::cout << oss.str();
Alternatively, you can just convert the integer and append it to the string.
oss << i;
text += oss.str();
Finally, the Boost libraries provide boost::lexical_cast, which wraps around the stringstream conversion with a syntax like the built-in type casts.
#include <boost/lexical_cast.hpp>
text += boost::lexical_cast<std::string>(i);
This also works the other way around, i.e. to parse strings.
printf("Player %d", i);
(Downvote my answer all you like; I still hate the C++ I/O operators.)
:-P
These work for general strings (in case you do not want to output to file/console, but store for later use or something).
boost.lexical_cast
MyStr += boost::lexical_cast<std::string>(MyInt);
String streams
//sstream.h
std::stringstream Stream;
Stream.str(MyStr);
Stream << MyInt;
MyStr = Stream.str();
// If you're using a stream (for example, cout), rather than std::string
someStream << MyInt;
For the record, you can also use a std::stringstream if you want to create the string before it's actually output.
cout << text << " " << i << endl;
Your example seems to indicate that you would like to display the a string followed by an integer, in which case:
string text = "Player: ";
int i = 4;
cout << text << i << endl;
would work fine.
But, if you're going to be storing the string places or passing it around, and doing this frequently, you may benefit from overloading the addition operator. I demonstrate this below:
#include <sstream>
#include <iostream>
using namespace std;
std::string operator+(std::string const &a, int b) {
std::ostringstream oss;
oss << a << b;
return oss.str();
}
int main() {
int i = 4;
string text = "Player: ";
cout << (text + i) << endl;
}
In fact, you can use templates to make this approach more powerful:
template <class T>
std::string operator+(std::string const &a, const T &b){
std::ostringstream oss;
oss << a << b;
return oss.str();
}
Now, as long as object b has a defined stream output, you can append it to your string (or, at least, a copy thereof).
Another possibility is Boost.Format:
#include <boost/format.hpp>
#include <iostream>
#include <string>
int main() {
int i = 4;
std::string text = "Player";
std::cout << boost::format("%1% %2%\n") % text % i;
}
Here a small working conversion/appending example, with some code I needed before.
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int main(){
string str;
int i = 321;
std::stringstream ss;
ss << 123;
str = "/dev/video";
cout << str << endl;
cout << str << 456 << endl;
cout << str << i << endl;
str += ss.str();
cout << str << endl;
}
the output will be:
/dev/video
/dev/video456
/dev/video321
/dev/video123
Note that in the last two lines you save the modified string before it's actually printed out, and you could use it later if needed.
For the record, you could also use Qt's QString class:
#include <QtCore/QString>
int i = 4;
QString qs = QString("Player %1").arg(i);
std::cout << qs.toLocal8bit().constData(); // prints "Player 4"
cout << text << i;
One method here is directly printing the output if its required in your problem.
cout << text << i;
Else, one of the safest method is to use
sprintf(count, "%d", i);
And then copy it to your "text" string .
for(k = 0; *(count + k); k++)
{
text += count[k];
}
Thus, you have your required output string
For more info on sprintf, follow:
http://www.cplusplus.com/reference/cstdio/sprintf
cout << text << i;
The << operator for ostream returns a reference to the ostream, so you can just keep chaining the << operations. That is, the above is basically the same as:
cout << text;
cout << i;
cout << "Player" << i ;
cout << text << " " << i << endl;
The easiest way I could figure this out is the following..
It will work as a single string and string array.
I am considering a string array, as it is complicated (little bit same will be followed with string).
I create a array of names and append some integer and char with it to show how easy it is to append some int and chars to string, hope it helps.
length is just to measure the size of array. If you are familiar with programming then size_t is a unsigned int
#include<iostream>
#include<string>
using namespace std;
int main() {
string names[] = { "amz","Waq","Mon","Sam","Has","Shak","GBy" }; //simple array
int length = sizeof(names) / sizeof(names[0]); //give you size of array
int id;
string append[7]; //as length is 7 just for sake of storing and printing output
for (size_t i = 0; i < length; i++) {
id = rand() % 20000 + 2;
append[i] = names[i] + to_string(id);
}
for (size_t i = 0; i < length; i++) {
cout << append[i] << endl;
}
}
There are a few options, and which one you want depends on the context.
The simplest way is
std::cout << text << i;
or if you want this on a single line
std::cout << text << i << endl;
If you are writing a single threaded program and if you aren't calling this code a lot (where "a lot" is thousands of times per second) then you are done.
If you are writing a multi threaded program and more than one thread is writing to cout, then this simple code can get you into trouble. Let's assume that the library that came with your compiler made cout thread safe enough than any single call to it won't be interrupted. Now let's say that one thread is using this code to write "Player 1" and another is writing "Player 2". If you are lucky you will get the following:
Player 1
Player 2
If you are unlucky you might get something like the following
Player Player 2
1
The problem is that std::cout << text << i << endl; turns into 3 function calls. The code is equivalent to the following:
std::cout << text;
std::cout << i;
std::cout << endl;
If instead you used the C-style printf, and again your compiler provided a runtime library with reasonable thread safety (each function call is atomic) then the following code would work better:
printf("Player %d\n", i);
Being able to do something in a single function call lets the io library provide synchronization under the covers, and now your whole line of text will be atomically written.
For simple programs, std::cout is great. Throw in multithreading or other complications and the less stylish printf starts to look more attractive.
You also try concatenate player's number with std::string::push_back :
Example with your code:
int i = 4;
string text = "Player ";
text.push_back(i + '0');
cout << text;
You will see in console:
Player 4
You can use the following
int i = 4;
string text = "Player ";
text+=(i+'0');
cout << (text);
If using Windows/MFC, and need the string for more than immediate output try:
int i = 4;
CString strOutput;
strOutput.Format("Player %d", i);