Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Mopp
Oct 29, 2004

I'm a beginner at C++, and I'm stuck at a task I'm doing. I've created a class Money that looks like this:

code:
class money {
public:
...
private: 
string curr;
int units;
int hundreds;
};
I've changed the operator << so it takes an ostream and prints the contents of Money. For example, cout << M; would print USD 00.00. Now I want to overload >>, so that I can take any istream and do something like cin >> M2; and then type EUR 10, or just 5 (curr ="") or 2.50 and construct M2 from that. I suppose I want to read the input character by character but have no idea how to approach this, I've never done it before. Anyone that could give me a clue?

Adbot
ADBOT LOVES YOU

HFX
Nov 29, 2004

Mopp posted:

I'm a beginner at C++, and I'm stuck at a task I'm doing. I've created a class Money that looks like this:

code:
class money {
public:
...
private: 
string curr;
int units;
int hundreds;
};
I've changed the operator << so it takes an ostream and prints the contents of Money. For example, cout << M; would print USD 00.00. Now I want to overload >>, so that I can take any istream and do something like cin >> M2; and then type EUR 10, or just 5 (curr ="") or 2.50 and construct M2 from that. I suppose I want to read the input character by character but have no idea how to approach this, I've never done it before. Anyone that could give me a clue?

cin.getline() [char array strings] and getline() [Object strings] would be your friends here.

Mopp
Oct 29, 2004

HFX posted:

cin.getline() [char array strings] and getline() [Object strings] would be your friends here.

Yeah, I don't get how to use getline correctly. I'm pretty much stuck at this:

code:
  void Money::insert(istream& is) {
    string tmp;
    while (is) {
      getline(is, tmp, '.');
    }
  }
  
  istream& operator>>(istream& is, Money& M) {
    M.insert(is);
    return is;
  }
Now I have a bunch of problems. I want to check if the input format is correct (only alphanumeric characters and a ',' allowed), and I need a bunch of cases. If the input is only a string, set curr = tmp and units, hundreds = 0. If the input is a digit, set units = [the digit] and so on.

Am I making this way harder than it is?

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


pseudorandom name posted:

Getting the source file and line number information would require interpreting the DWARF information, which is much more involved than just figuring out which dynamic symbol (probably) contains the address.

DWARF information isn't even available unless I compile in debug mode, right? (in solaris, CC -g or -g0 as opposed to CC -xO3 for optimized)

epswing
Nov 4, 2003

Soiled Meat
Common occurrence in Java:
code:
Reader r = blah
String s = "";
while ((s = r.read()) != null) {
    // do stuff with s
}
The read() function will give you a string, or null if something happens that isn't an exception (eg. you're at EOF, the stream closes, etc).

I have a C++ function that reads from a pipe (using ReadFile) and returns a std::string (it looks like std::string Read()). When the pipe closes, ReadFile returns false, GetLastError() gives me ERROR_BROKEN_PIPE, that's all well and good. Instinctively (possibly because Java has damaged my brain) I want to return null, but NULL in C++ means a "pointer to NULL" I think, so checking if (s != NULL) isn't going to work.

What is The Right Way to handle this? Should it be std::string* Read() (which I can check against NULL)?

Edit: or maybe...should my prototype be void Read(std::string& s)?

epswing fucked around with this message at 18:38 on Sep 30, 2010

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

epswing posted:

Edit: or maybe...should my prototype be void Read(std::string& s)?
You'd want bool Read(std::string& s) if you're going to do it that way - you still want a return value to check for end condition.

epswing
Nov 4, 2003

Soiled Meat
Yes! Thank you!

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Another memory leak-fix fiasco has sent me over the edge. It's too late to fix our code by switching to boost::shared_ptrs (and my coworkers would throw a fit because that would be "unreadable" :psyduck: ), but since we're on Solaris I just realized an alternate solution is available: linking to a garbage collector, libgc.

I'm reading what I can on this thing, but in the meantime, are there any major gotchas or pitfalls to using a garbage collector in C++ that I need to think about?

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
The collector shipped with Sun Studio is implemented with the Boehm collector, which is well-used. Just test it out first, because this (old) link indicates that it uses an old version of Boehm. If it's been updated, I can't find any info on it. There are also more things to watch out for when using the collector for C++ versus C, but it seems like the Sun library does a decent job of wrapping things up, so maybe you'll be okay.

pseudorandom name
May 6, 2007

Ledneh posted:

DWARF information isn't even available unless I compile in debug mode, right? (in solaris, CC -g or -g0 as opposed to CC -xO3 for optimized)

Yes. Although you should be able to build fully optimized with debugging information enabled. (gcc accepts both -O3 and -g at the same time, I don't know about Sun Studio.)

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


pseudorandom name posted:

Yes. Although you should be able to build fully optimized with debugging information enabled. (gcc accepts both -O3 and -g at the same time, I don't know about Sun Studio.)

That I didn't know, I thought one ran exclusive to the other. Though I guess including debug info would only raise the size of the compile results, now that I actually think about it (I've never tried vOv).


Regarding that garbage collector (and please bear with me, I'm new to the whole subject), if an object is leaked then later the GC tries to reclaim that memory, is that leaked object's destructor called, or is the memory straight up freed and drat the consequences?

Vanadium
Jan 8, 2005

Who knows. Garbage collectors are crazy like that.

Mopp
Oct 29, 2004

Mopp posted:

Yeah, I don't get how to use getline correctly. I'm pretty much stuck at this:


Now I have a bunch of problems. I want to check if the input format is correct (only alphanumeric characters and a ',' allowed), and I need a bunch of cases. If the input is only a string, set curr = tmp and units, hundreds = 0. If the input is a digit, set units = [the digit] and so on.

Am I making this way harder than it is?

So I kind of solved my problem, but I'm still having difficulties. My function look like this:

code:
 void Money::insert(istream& is) {
     string tmpcurr;
     int tmpu, tmph;
     is >> ws;                  
     if (isalpha(is.peek())) 
       is >> tmpcurr;
     is >> tmpu;
     
     if (ispunct(is.peek())) {
       is >> tmph;
       cout << tmph << endl;
     }
     Money tmp(tmpcurr,tmpu,tmph);
     *this=tmp;
  }
  
  istream& operator>>(istream& is, Money& M) {
    M.insert(is);
    return is;
  }
and my main that calls for this is:
code:
 
int main() {
Money M;
    cin >> M;
    cout << "M = " << M << endl;
    return 0;
}
problem is that while I input "USD 20.50", it returns "USD 20.00". What have I missed?

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

Ledneh posted:

Regarding that garbage collector (and please bear with me, I'm new to the whole subject), if an object is leaked then later the GC tries to reclaim that memory, is that leaked object's destructor called, or is the memory straight up freed and drat the consequences?
The destructor is automatically called if the class inherits from gc_cleanup. You can also explicitly specify cleanup functions when you call new. More details in the opening comment here.

Grazing Occultation
Aug 18, 2009

by angerbutt

Mopp posted:

So I kind of solved my problem, but I'm still having difficulties. My function look like this:

code:
 void Money::insert(istream& is) {
     string tmpcurr;
     int tmpu, tmph;
     is >> ws;                  
     if (isalpha(is.peek())) 
       is >> tmpcurr;
     is >> tmpu;
     
     if (ispunct(is.peek())) {
       is >> tmph;
       cout << tmph << endl;
     }
     Money tmp(tmpcurr,tmpu,tmph);
     *this=tmp;
  }
  
  istream& operator>>(istream& is, Money& M) {
    M.insert(is);
    return is;
  }
and my main that calls for this is:
code:
 
int main() {
Money M;
    cin >> M;
    cout << "M = " << M << endl;
    return 0;
}
problem is that while I input "USD 20.50", it returns "USD 20.00". What have I missed?

The problem is that you're reading "20.50" as two integers back to back. ie. It reads "20", leaving ".50", which won't be read properly as an integer.

You probably want to read the 20.50 as a floating point, not an integer - replacing tmpu and tmph with a single variable.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Mustach posted:

The destructor is automatically called if the class inherits from gc_cleanup. You can also explicitly specify cleanup functions when you call new. More details in the opening comment here.

One last (and more general) question, then. Does having a working garbage collector give the users carte blanche to comment out their deletes (and most destructors), since the GC will take care of it later? Or would counting on the GC as a rule cause a gross performance impact? (Or maybe even a performance boost, if destructors don't need to be called anymore? I don't know, I'm talking out of my rear end here.)

Ciaphas fucked around with this message at 21:33 on Sep 30, 2010

Mopp
Oct 29, 2004

Grazing Occultation posted:

The problem is that you're reading "20.50" as two integers back to back. ie. It reads "20", leaving ".50", which won't be read properly as an integer.

You probably want to read the 20.50 as a floating point, not an integer - replacing tmpu and tmph with a single variable.

No, this is an exercise for a course that I'm taking. It requires two different integers.

edit: the problem remains, there's an error in the code up there since it manages to enter the if(ispunct(is.peek())), but temph remains 0.

Mopp fucked around with this message at 21:44 on Sep 30, 2010

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Mopp posted:

edit: the problem remains, there's an error in the code up there since it manages to enter the if(ispunct(is.peek())), but temph remains 0.
That's what Grazing Occultation said was happening - it enters that because ".50" "ispunct"[uation], but then you try to get the integer from the string ".50", which isn't an integer, because integers don't begin with a "." - you have to strip that off after the punctuation is matched and before you try to read an integer.

king_kilr
May 25, 2007

Grazing Occultation posted:

The problem is that you're reading "20.50" as two integers back to back. ie. It reads "20", leaving ".50", which won't be read properly as an integer.

You probably want to read the 20.50 as a floating point, not an integer - replacing tmpu and tmph with a single variable.

If you treat money as a floating point, I will find you and hurt you.

Mopp
Oct 29, 2004

roomforthetuna posted:

That's what Grazing Occultation said was happening - it enters that because ".50" "ispunct"[uation], but then you try to get the integer from the string ".50", which isn't an integer, because integers don't begin with a "." - you have to strip that off after the punctuation is matched and before you try to read an integer.

well that was something that I missed. It works great now, thanks for the help!

ToxicFrog
Apr 26, 2008


Ledneh posted:

That I didn't know, I thought one ran exclusive to the other. Though I guess including debug info would only raise the size of the compile results, now that I actually think about it (I've never tried vOv).

Depending on circumstances, using optimization and debug together can result in some confusion - things you expect to be examinable being optimized away, confusion about line numbers - but it won't break anything.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Ledneh posted:

One last (and more general) question, then. Does having a working garbage collector give the users carte blanche to comment out their deletes (and most destructors), since the GC will take care of it later? Or would counting on the GC as a rule cause a gross performance impact? (Or maybe even a performance boost, if destructors don't need to be called anymore? I don't know, I'm talking out of my rear end here.)
With a good GC it'll improve performance at the cost of memory usage as the GC can do the deleting when the program is idle. With a bad GC (or a program that is never idle), it'll potentially kill performance by doing the deleting at all the wrong times.

In most cases it'll have no noticeable impact.

POKEMAN SAM
Jul 8, 2004

king_kilr posted:

If you treat money as a floating point, I will find you and hurt you.

This needs to be reiterated because it wasn't replied to.

Optimus Prime Ribs
Jul 25, 2007

I feel dumb.
I for the life of me cannot figure out how to get my method of a class template to work. All I'm getting is an unresolved external for my constructor, but I can't tell where I hosed up.

code:
#ifndef _TEST_H_
#define _TEST_H_

template <class _Ty>
class testing
{
private:
    //
public:
    testing();
};

#endif
code:
#include "test.h"

template <class _Ty>
testing<_Ty>::testing()
{
    //
}
What's going on here? :(

OddObserver
Apr 3, 2009
^^^^^
put your implementation in the header. It can't get instantiated from the .cpp

And on an unrelated note:

Ugg boots posted:

king_kilr posted:

If you treat money as a floating point, I will find you and hurt you.

This needs to be reiterated because it wasn't replied to.

To elaborate, I am pretty sure you can't accurately represent numbers as simple as 0.10 (e.g. 10 cents) in (binary) floating point.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

OddObserver posted:

To elaborate, I am pretty sure you can't accurately represent numbers as simple as 0.10 (e.g. 10 cents) in (binary) floating point.
You'd get the occasional rounding error up or down a cent, yeah. Also, more importantly, you'd lose precision at larger numbers, and there's really no reason at all not to just store money as a single integer representing cents, which you can print as (money/100) + "." + (money%100).

Maybe not necessarily 100 for some currencies, but whatever, currency can always be stored as an integer number of whatever the smallest unit of currency is. So when England still had half-pennies it could have been output as (money/200) + "." + ((money%200)/2) + ((money%2)?" and a half penny":"")

(You'd probably want to use a 64-bit integer, since $43M isn't a very high limit, but 184 quadrillion dollars should work out okay. Or 92 quadrillion if you're allowing negatives.)

As an example of floats losing precision at higher numbers:
code:
 float x=100000.00f;
 x+=0.01f;
 printf("%f\n",x);
 x+=0.01f;
 printf("%f\n",x);
 x=100000.00f;
 x+=0.02f;
 printf("%f\n",x);
Outputs
code:
100000.007813
100000.015625
100000.023438
Yeah, 1 penny plus 1 penny = 1.5625 pennies, but 2 pennies = 2.3438 pennies!

Edit: Also, if you add one or two pennies to a million, it's just flat lost.

roomforthetuna fucked around with this message at 02:20 on Oct 1, 2010

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Another question on the Boehm-Demers-Weiser GC. Is there some magic incantation I have to perform to make datain STL containers traceable (if not collectable)? In my test code so far I'm getting objects deleted prematurely everywhere, seemingly becauseit isn't tracking pointers stored in STL maps.

OddObserver
Apr 3, 2009

Ledneh posted:

Another question on the Boehm-Demers-Weiser GC. Is there some magic incantation I have to perform to make datain STL containers traceable (if not collectable)? In my test code so far I'm getting objects deleted prematurely everywhere, seemingly becauseit isn't tracking pointers stored in STL maps.

IIRC, You need to get it to use GC_alloc for memory. Hopefully it provides an allocator...

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
Yes, it provides an allocator. See this link that I linked, under "C++ Interface".

ehnus
Apr 16, 2003

Now you're thinking with portals!

Ledneh posted:

Another memory leak-fix fiasco has sent me over the edge. It's too late to fix our code by switching to boost::shared_ptrs (and my coworkers would throw a fit because that would be "unreadable" :psyduck: ), but since we're on Solaris I just realized an alternate solution is available: linking to a garbage collector, libgc.

I'm reading what I can on this thing, but in the meantime, are there any major gotchas or pitfalls to using a garbage collector in C++ that I need to think about?

Is it possible to override new/delete/malloc/free/etc. so that they capture a callstack (or partial callstack) for every allocation and then have it log what wasn't cleaned up on exit?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

ehnus posted:

Is it possible to override new/delete/malloc/free/etc. so that they capture a callstack (or partial callstack) for every allocation and then have it log what wasn't cleaned up on exit?
Not sure if you mean this question as "in his situation" or "in general". In general, yes, it is certainly possibly, because I have a little library I use for all my debug code that does a simplistic version of that (as well as doing the same thing for most of the common Windows resource allocation/deallocation pairings, like CreateBitmap etc.)

It goes something like this:
code:
void * __cdecl operator new[](size_t size,LPCTSTR fname,int line) {return RMalloc(size,fname,line);}
void * __cdecl operator new(size_t size,LPCTSTR fname,int line) {return RMalloc(size,fname,line);}
void __cdecl operator delete[](void *p) {RFree(p,_T(__FILE__),__LINE__);}
void __cdecl operator delete[](void *p,LPCTSTR fname,int line) {RFree(p,fname,line);}
void __cdecl operator delete(void *p,LPCTSTR fname,int line) {RFree(p,fname,line);}

#define new new(__FILE__,__LINE__)
#define malloc(sz) RMalloc(sz,__FILE__,__LINE__)
#define free(p) RFree(p,__FILE__,__LINE__)
Then RMalloc records the filename, line number and allocated address (indexed by the address) then returns a standard malloc of the size, and RFree erases the entry with the given address and performs a standard free, or outputs the file and line number in which you tried to free something that wasn't in the list.

I also have a "DebugStart()" function that sets up the recording structure, and "DebugEnd()" that outputs all the stuff, though you could do that with a global object's constructor and destructor instead. The one gotcha I found with this setup is that if you allocate stuff in the constructor of a global object (ie. before 'main') or destroy it in the destructor of a global object (ie. after 'main' ends) then it's not good. (Also, make sure you don't have the #define'd new/malloc being used for allocation within your logging stuff, you don't want it to start logging itself.)

roomforthetuna fucked around with this message at 08:10 on Oct 1, 2010

ehnus
Apr 16, 2003

Now you're thinking with portals!
I meant in his situation, it's a technique I use fairly often for tracking down memory leaks.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Mustach posted:

Yes, it provides an allocator. See this link that I linked, under "C++ Interface".

Thanks, sorry, my reading comprehension has apparently gone straight to poo poo today. :(

Thanks for the new/delete logging suggestion too, if I can't get the garbage collector functional I'll see if that'll help, I don't see any reason that can't work in our codebase :)


(edit) Is there any template or typedef fuckery I can do to make something like this work? (I know template typedefs can't happen, this is just to demo what I want)
code:
template <typename key, typename val>
typedef std::map<key, val, whateverthedefaultcomparatoris, gc_allocator<key, val> > GcMap<key, val>;

Ciaphas fucked around with this message at 08:13 on Oct 1, 2010

litghost
May 26, 2004
Builder

Ledneh posted:

Thanks, sorry, my reading comprehension has apparently gone straight to poo poo today. :(

Thanks for the new/delete logging suggestion too, if I can't get the garbage collector functional I'll see if that'll help, I don't see any reason that can't work in our codebase :)


(edit) Is there any template or typedef fuckery I can do to make something like this work? (I know template typedefs can't happen, this is just to demo what I want)
code:
template <typename key, typename val>
typedef std::map<key, val, whateverthedefaultcomparatoris, gc_allocator<key, val> > GcMap<key, val>;

code:
template<typename key, typename val, typename BinPred = std::less<key> >
struct GcMap :
	std::map<
		 key, 
		 val, 
		 BinPred, 
		 gc_allocator<std::pair<key, val> > 
                > 
{};

Mopp
Oct 29, 2004

drat it, just when I thought I managed to fix all errors this happens.

I'm still using my money class, and I'm writing a program to test it's functionality. However, it returns a seg fault. I know that the "=" operator works fine since I can construct Money M("USD, 20, 50), Money M2, and then use M2=M.

Money has three parameters, string curr, int units and int hundreds.

The problem is when I try to set Money M3 = M + M2.

Here is the code:

code:
Money Money::operator+(const Money& m) {
    if (curr != m.curr && curr != "" && m.curr != "") 
      throw monetary_error("error: can't add different currencies");
    int u = units + m.units;
    int h = hundreds + m.hundreds;
    Money tmp;
    if (h > 99) {
      u=u+1;
      h=h-100;
    } 
    if (curr == m.curr || m.curr == "") {
      Money r(curr,u,h);
      tmp=r;
    }
    if (curr == ""); {
      Money r(m.curr,u,h);
      tmp=r;
    }
    return tmp;
  }
In my program I try to add SEK 0.00 to SEK 10.00, and it's a valid operation. It calls for the "="-operator which looks like this:

code:
    Money& Money::operator=(const Money& r) {
    if (curr != r.curr && curr != "" && r.curr != "") 
      throw monetary_error("not allowed to reassign currencies");
    if (curr == "") curr = r.curr;
    units = r.units;
    hundreds = r.hundreds;
    return *this;
  }
The program runs fine until return *this;, then it segfaults. Could anyone more experienced with this spot the problem?

Grazing Occultation
Aug 18, 2009

by angerbutt

king_kilr posted:

If you treat money as a floating point, I will find you and hurt you.

Hahaha I don't deal with money at all. I'm sure I do more than a few things that would make you want to hurt me anyway though. v:shobon:v

(Any suggestion on good resources describing pitfalls and how to handle currency properly? Now I'm curious.)

Jonnty
Aug 2, 2007

The enemy has become a flaming star!

Grazing Occultation posted:

Hahaha I don't deal with money at all. I'm sure I do more than a few things that would make you want to hurt me anyway though. v:shobon:v

(Any suggestion on good resources describing pitfalls and how to handle currency properly? Now I'm curious.)

"don't use a datatype that will make your clients' money randomly disappear" is pretty much it

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


roomforthetuna posted:

Not sure if you mean this question as "in his situation" or "in general". In general, yes, it is certainly possibly, because I have a little library I use for all my debug code that does a simplistic version of that (as well as doing the same thing for most of the common Windows resource allocation/deallocation pairings, like CreateBitmap etc.)

It goes something like this:
:words:

Would I also need to #define delete and delete[] to RFree as you did with free?

Ciaphas fucked around with this message at 15:58 on Oct 1, 2010

Lexical Unit
Sep 16, 2003

Mopp posted:

The program runs fine until return *this;, then it segfaults. Could anyone more experienced with this spot the problem?
Testing using your code didn't produce a segfault for me. We need to see where you're calling operator+() and operator=(). Also, I'm going to give you some free advice that will make your life easier.

Implement operator=() like this:
code:
void money::swap(money& other)
{
	using std::swap;
	swap (currency, other.currency);
	swap (units, other.units);
	swap (hundreds, other.hundreds);
}

money& money::operator=(money other)
{
	swap (other);
	return *this;
}
And implement operator+() like this:
code:
money& money::operator+=(const money& rhs)
{
	hundreds += rhs.hundreds;
	units += rhs.units + hundreds / 100;
	hundreds %= 100;
	return *this;
}

money operator+(money lhs, const money& rhs)
{
	return lhs += rhs;
}
\/\/ True. Fixed. Better to learn idioms by example, I think. Before moving on to simply using Boost.

Lexical Unit fucked around with this message at 16:34 on Oct 1, 2010

Adbot
ADBOT LOVES YOU

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
operator+ doesn't need to be a friend. Also, as usual, there's a Boost for that.

Mustach fucked around with this message at 16:22 on Oct 1, 2010

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply