I have been looking through the API for TinyXML and I can't find a way to check if an element exists before I try and get it by name. I have commented what I am looking for below:
#include <iostream>
#include "tinyxml.h"
int main()
{
const char* exampleText = "<test>\
<field1>Test Me</field1>\
<field2>And Me</field2>\
</test>";
TiXmlDocument exampleDoc;
exampleDoc.Parse(exampleText);
// exampleDoc.hasChildElement("field1") { // Which doesn't exist
std::string result = exampleDoc.FirstChildElement("test")
->FirstChildElement("field1")
->GetText();
// }
std::cout << "The result is: " << result << std::endl;
}
The FirstChildElement function will return a pointer, so that pointer can be used in the if-statement like so.
#include <iostream>
#include "tinyxml.h"
int main()
{
const char* exampleText = "<test>\
<field1>Test Me</field1>\
<field2>And Me</field2>\
</test>";
TiXmlDocument exampleDoc;
exampleDoc.Parse(exampleText);
TiXmlElement* field1 = exampleDoc.FirstChildElement("test")
->FirstChildElement("field1");
if (field1) {
std::string result = field1->GetText();
std::cout << "The result is: " << result << std::endl;
}
}
I am learning boost::asio, and encountered a problem. Basically, asio::buffer_cast() works strange on my machine. Any help would be greatly appreciated.
I have sample code as follows,
#include <iostream>
#include <vector>
#include <sstream>
#include <iomanip>
#include <boost/asio.hpp>
int main ()
{
std::ostringstream type_stream;
type_stream << std::setw(4) << 100;
std::cout<<"type_stream:"<<type_stream.str()<<std::endl;
std::ostringstream head_stream;
head_stream << std::setw(10) << 92;
std::cout<<"head_stream:"<<head_stream.str()<<std::endl;
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(type_stream.str()));
buffers.push_back(boost::asio::buffer(head_stream.str()));
auto test = buffers[0];
const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(test);
std::cout<<"type_stream again:"<<std::string(reinterpret_cast<const char*>(p1))<<std::endl;
auto test2 = buffers[1];
const unsigned char* p2 = boost::asio::buffer_cast<const unsigned char*>(test2);
std::cout<<"head_stream again:"<<std::string(reinterpret_cast<const char*>(p2))<<std::endl;
return 0;
}
If you run this code here: https://wandbox.org/permlink/4VkxJ4TFgjHzrath, it works fine. The output is
type_stream: 100
head_stream: 92
type_stream again: 100
head_stream again: 92
But when put the code in a function and run on my machine, I got output as
type_stream: 100
head_stream: 92
type_stream again: 92
head_stream again: 92
Am I doing anything wrong in the code? It seems on my machine the second buffer covered the first one. I have gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0, and the newest boost::asio.
Yes, there's Undefined Behaviour.
The problem is that
buffers.push_back(boost::asio::buffer(type_stream.str()));
the type_stream.str() returns a temporary std::string and therefore the buffer isn't valid after the push.
Fix:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
std::string format_buf(int v, int width) {
std::ostringstream oss;
oss << std::setw(width) << v;
return oss.str();
}
int main() {
std::string type_str = format_buf(100, 4);
std::string head_str = format_buf(92, 10);
std::cout << "type_stream first: " << std::quoted(type_str) << std::endl;
std::cout << "head_stream first: " << std::quoted(head_str) << std::endl;
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(type_str));
buffers.push_back(boost::asio::buffer(head_str));
auto test = buffers[0];
const unsigned char *p1 = boost::asio::buffer_cast<const unsigned char *>(test);
std::cout << "type_stream again:" << std::quoted(reinterpret_cast<const char *>(p1)) << std::endl;
auto test2 = buffers[1];
const unsigned char *p2 = boost::asio::buffer_cast<const unsigned char *>(test2);
std::cout << "head_stream again:" << std::quoted(reinterpret_cast<const char *>(p2)) << std::endl;
}
Prints
type_stream first: " 100"
head_stream first: " 92"
type_stream again:" 100"
head_stream again:" 92"
BONUS
Since you're effectively trying to do fixed-width formatting (?) why not make it simpler and more robust:
Live On Coliru
char type[4] = {};
char head[10] = {};
bio::stream<bio::array_sink> tstream(type);
tstream << 100;
bio::stream<bio::array_sink> hstream(head);
hstream << 92;
It's more robust because with your code the fields may be too wide (e.g. with type containing 12345)
With help from #sehe, the following code works. But I got new worries. Is it okay to create char type[4] = {}; char head[10] = {}; char type2[2] = {}; inside prepareBuffers() function? As the buffer was created by buffers.push_back(boost::asio::buffer(type));, I suspect type will be destroyed when goes out of prepareBuffers() function. But the in the main() the program still can access the content of buffer. Is there any copy happens?
#include <boost/asio.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
namespace bio = boost::iostreams;
void prepareBuffers(std::vector<boost::asio::const_buffer> & buffers){
char type[4] = {};
char head[10] = {};
bio::stream<bio::array_sink> tstream(type);
bio::stream<bio::array_sink> hstream(head);
tstream << 555555;
hstream << 923;
std::cout << "type_stream first: " << std::quoted(type) << std::endl;
std::cout << "head_stream first: " << std::quoted(head) << std::endl;
buffers.push_back(boost::asio::buffer(type));
buffers.push_back(boost::asio::buffer(head));
auto test = buffers[0];
const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(test);
std::cout<<"in function type_stream again:"<<std::string(reinterpret_cast<const char*>(p1))<<std::endl;
test = buffers[1];
const unsigned char* p2 = boost::asio::buffer_cast<const unsigned char*>(test);
std::cout<<"in function head_stream again:"<<std::string(reinterpret_cast<const char*>(p2))<<std::endl;
}
int main() {
std::vector<boost::asio::const_buffer> buffers2;
prepareBuffers(buffers2);
auto test21 = buffers2[0];
const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(test21);
std::cout<<"type_stream again:"<<std::string(reinterpret_cast<const char*>(p1))<<std::endl;
auto test22 = buffers2[1];
const unsigned char* p2 = boost::asio::buffer_cast<const unsigned char*>(test22);
std::cout<<"type_stream again:"<<std::string(reinterpret_cast<const char*>(p2))<<std::endl;
return 0;
}
I'm trying to use a setter function inside of a constructor, which I've never done before. It's giving me the following error:
[Error] no match for call to '(Laptop) (const char [5], const char [3], int, int)'
well do i need to write the setter function too ? i mean outside the constructor ? i mean like this
void Laptop::setBrand(char a[])
{
brand=a;}
I think the error is in the second constructor, that takes four arguments, but I'm not able to find it.
Here is the code:
#include <iostream>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
using namespace std;
class Laptop{
private:
char brand[10];
char processor[10];
int ram;
int hardDrive;
public:
void setBrand(char Bra[]);
void setProcessor(char Pro[]);
void setRam(int Ram);
void setHardDrive(int HDrive);
char *getBrand();
char *getProcessor();
int getRam();
int getHardDrive();
Laptop();
Laptop(char [],char [],int ,int );
};
Laptop::Laptop(){
cout<<"Default constructor called...\n";
strcpy(brand,"None");
strcpy(processor,"None);
ram=0;
hardDrive=0;
}
i think the error is in the constructor
Laptop::Laptop(char Bra[],char Pro[],int Ram,int HDrive)
{
cout<<"Parameterized constructor called...\n";
setBrand(Bra );
setProcessor(Pro );
setRam(Ram);
setHardDrive(HDrive);
}
char *Laptop::getBrand()
{
return brand;
}
char *Laptop::getProcessor()
{
return processor;
}
int Laptop::getRam()
{
return ram;
}
int Laptop::getHardDrive()
{
return hardDrive;
}
int main()
{
Laptop laptopObj1;
Laptop laptopobj1("Dell","i5",4,500);
cout<<"Brand :"<<laptopObj1.getBrand()<<"\n";
cout<<"Processor :"<<laptopObj1.getProcessor()<<"\n";
cout<<"Ram :"<<laptopObj1.getRam()<<"\n";
cout<<"HardDrive :"<<laptopObj1.getHardDrive()<<"\n";
cout<<"Brand :"<<laptopObj2.getBrand()<<"\n";
cout<<"Processor :"<<laptopObj2.getProcessor()<<"\n";
cout<<"Ram :"<<laptopObj2.getRam()<<"\n";
cout<<"HardDrive :"<<laptopObj2.getHardDrive()<<"\n";
}
You have alot of errors here..
Laptop laptopObj1,laptopObj2;
...
laptopObj2("Dell","i5", 4, 500);
You cant use the constructor twice. You used the constructor Laptop() in the first line for both of the object, and then tried to use the second constructor for laptopObj2.
You can change the second line to:
laptopObj2 = Laptop("Dell","i5", 4, 500);
Or even better to define it there:
Laptop laptopObj1;
....
Laptop laptopObj2("Dell","i5", 4, 500);
Another problem is inside your Laptop() constructor definition:
Laptop::Laptop(char Bra[],char Pro[],int Ram,int HDrive)
{
.....
setBrand(Bra []); // Remove the []
setProcessor(Pro []); // Remove the []
....
}
And one more problem: You have no definitions for some functions of the class:
void setBrand(char Bra[]);
void setProcessor(char Pro[]);
void setRam(int Ram);
void setHardDrive(int HDrive);
void display();
EDIT:
One of the objects of c++ is std::string (#include <string>). You can use it instead of char str[]- just simpler way to declare strings in c++. For example, in your case:
/* Replace this: */
char brand[10];
char processor[10];
void setBrand(char Bra[]);
void setProcessor(char Pro[]);
char *getBrand();
char *getProcessor();
/* With this: */
string brand;
string processor;
void setBrand(const string &Bra);
void setProcessor(const string &Pro);
string getBrand();
string getProcessor();
You are passing two const char* as parameter, so you should change this :
Laptop::Laptop(char Bra[],char Pro[],int Ram,int HDrive)
to this:
Laptop::Laptop(const char* ,const char* ,int Ram,int HDrive)
You really should use std::string rather than char[].
On the question of constructors, there is no need to call setters, as the following code demonstrates. C++ has a shortcut for that capability. I have used std::string and fixed all typos.
#include <iostream>
#include <string>
using namespace std;
class Laptop
{
private:
string brand;
string processor;
int ram;
int hardDrive;
public:
void setBrand(string Bra);
void setProcessor(string Pro);
void setRam(int Ram);
void setHardDrive(int HDrive);
string getBrand();
string getProcessor();
int getRam();
int getHardDrive();
Laptop();
Laptop(string, string, int, int);
};
Laptop::Laptop()
: brand("None")
, processor("None")
, ram(0)
, hardDrive(0)
{
cout << "Default constructor called...\n";
}
Laptop::Laptop(string Bra, string Pro, int Ram, int HDrive)
: brand(Bra)
, processor(Pro)
, ram(Ram)
, hardDrive(HDrive)
{
cout << "Parameterized constructor called...\n";
}
string Laptop::getBrand()
{
return brand;
}
string Laptop::getProcessor()
{
return processor;
}
int Laptop::getRam()
{
return ram;
}
int Laptop::getHardDrive()
{
return hardDrive;
}
int main()
{
Laptop laptopObj1;
Laptop laptopObj2("Dell", "i5", 4, 500);
cout << "Brand :" << laptopObj1.getBrand() << "\n";
cout << "Processor :" << laptopObj1.getProcessor() << "\n";
cout << "Ram :" << laptopObj1.getRam() << "\n";
cout << "HardDrive :" << laptopObj1.getHardDrive() << "\n";
cout << "Brand :" << laptopObj2.getBrand() << "\n";
cout << "Processor :" << laptopObj2.getProcessor() << "\n";
cout << "Ram :" << laptopObj2.getRam() << "\n";
cout << "HardDrive :" << laptopObj2.getHardDrive() << "\n";
}
Mike
I have this code below which parses a for statement, but I am not sure how to put any value into the ostream when calling the method write(...). What can I do? (e.g write("for (........."))
#include <ostream>
#include <iostream>
using namespace std;
//I cut out the declaration bit here
typedef const string type;
private:
type *initializer;
type *condition;
type *increment;
type *body;
public:
void write(ostream& stream) const {
stream
<< "for ("
<< *initializer << "; "
<< *condition << "; "
<< *increment << ")\n{\n"
<< *body
<< "}";
}
I guess you try to learn using ostream as an input in a function. But it seems that you mixing things that how to use classs and methods.
Maybe this is no avail but i can give you a little snippet to give you some opinion.
#include <iostream>
#include <string>
using namespace std;
typedef const string type;
type *init;
type *cond;
type *incr;
type *body;
void write(ostream& stream) {
stream
<< "for ("
<< *init << "; "
<< *cond << "; "
<< *incr << ")\n{\n"
<< *body
<< "\n}";
}
int main(int argc, char* argv[])
{
const string ini = "int i = 0";
const string con = "i < 10";
const string inc = "i++";
const string bod = "cout << i << endl;";
init = &ini;
cond = &con;
incr = &inc;
body = &bod;
write(cout);
return 0;
}
Try this code, examine and read more for more details.
So, when I pass a const char * to a function once, can I use it again? It appears to end up spitting out crap to me.
const char *config_file = "file.txt";
function(int x, config_file);
cout << "Number" << x;
secondfunction(int y, config_file);
Do I need to make another pointer to config_file?
If so, how do I do that?
Thanks!
No, your can use it just fine. Despite the fact that the code you gave is uncompilable, I think I understand what you're asking.
A code segment like:
const char *x = "Hello";
fnA (x);
fnB (x);
should be just fine.
If you find that fnB is not getting what it expects then either:
fnA is changing what x points to (normally not possible since it's a const char *); or
some unshown piece of code is changing the pointer itself; or
something is corrupting the memory.
Try this code as an example:
#include <iostream>
#include <iomanip>
static void fnA (const char *a) {
std::cout << "fnA: [" << a << "]" << std::endl;
}
static void fnB (const char *b) {
std::cout << "fnB: [" << b << "]" << std::endl;
}
int main (void) {
const char *x = "Hello";
fnA (x);
fnB (x);
return 0;
}
It outputs, as expected:
fnA: [Hello]
fnB: [Hello]