• Hey, guest user. Hope you're enjoying NeoGAF! Have you considered registering for an account? Come join us and add your take to the daily discourse.

C++ Help?

Status
Not open for further replies.

gosox333

Member
I need some help with this. I'm absolutely terrible at C++, I hate doing it, and the only reason I've gotten this far with this program is because I've had my friend help me with it. But now I'm in a situation where I can't have that friend help anymore.

All of that is basically just a disclaimer. If I'm missing something stupid, or have done something/everything completely wrong, that's why.


Code:
#include <iomanip>
#include <iostream>
#include <ctype.h>

using namespace std;

int isDigit(char ch); //Function 1
int isUpper(char ch); //Function 2
int isLower(char ch); //Function 3
int isAlpha(char ch); //Function 4

int main() //The boss function
{
    //Displays a title for the calculator
    cout << "\n===============================================================\n" << endl
         << "    ~  Welcome to Purple Prose Press Payment Calculator!  ~" << endl
         << "\n===============================================================\n" << endl
         << "   - Enter characters to calculate.\n" << endl
         << "   - Place an ! at the beginning of the line to quit.\n" << endl
         << "---------------------------------------------------------------\n" << endl;
         
    char ch;
    //Delcares variables
    int numDig, numUpp, numLow, numAlp, totLow, totDig, totUpp, totAlp, totCha;
    
    totDig = totUpp = totAlp = totLow = 0;
    
    ch = cin.get();
    
    while (ch != '!')
    {//Starts the first loop
         numDig = numUpp = numLow = numAlp = 0;
		  
          if (isUpper(ch)) //Refers function 2
		  	  numUpp++;
			   
          if (isLower(ch)) //Refers function 3
              numLow++;
          
          if (isDigit(ch)) //Refers function 1
              numDig++;
          
		  if (isAlpha(ch))
		  	  numAlp++;    //Refers function 4
          
          ch = cin.get();
    }
    
    //The += will add the individual sets if values and adds them up for the final info display
    totDig += numDig;
    totUpp += numUpp;
    totLow += numLow;
    totCha = numDig + numUpp + numLow;
    
    //These cout statements will display the values for the intial lines of characters
    cout << "   Upper case letters: \t\t\t" << numUpp << endl 
         << "   Lower case letters: \t\t\t" << numLow << endl
         << "   Digits: \t\t\t\t" << numDig << endl
		 << "   Characters: \t\t\t\t\t" << totCha << endl 
         << "\n---------------------------------------------------------------\n" << endl;
    ch = cin.get();
    } //Ends the first loop

    system ("pause")
    return 0;
} //Ends the boss function

int isDigit(char ch)
{
   if ((int)ch >= 48 && (int)ch <= 57)
      return 1;
   else
      return 0;
}

int isUpper(char ch)
{
   if ((int)ch >= 65 && (int)ch <= 90)
      return 1;
   else
      return 0;
}

int isLower(char ch)
{
   if ((int)ch >= 97 && (int)ch <= 122)
      return 1;
   else
      return 0;
}


int isAlpha(char ch)
{
	if ((int)ch >= 97 && (int)ch <= 27 || int(ch) >= 65 && int(ch) <= 90)
		return 1
	else
		return 0;
}

Anyways, I'm trying to get this to compile. I've gotten it down to two main errors. I have one "expected declaration before '}' tolken" on the bracket before my first function, and one "expected constructor, instructor, or type conversion before '(' tolken" on the system pause line.

Any ideas? I honestly don't even know what those mean....
 

Bruiserk

Member
I need some help with this. I'm absolutely terrible at C++, I hate doing it, and the only reason I've gotten this far with this program is because I've had my friend help me with it. But now I'm in a situation where I can't have that friend help anymore.

All of that is basically just a disclaimer. If I'm missing something stupid, or have done something/everything completely wrong, that's why.


CODE

Anyways, I'm trying to get this to compile. I've gotten it down to two main errors.

EDIT: Fixing the post. The image I uploaded was too big. One sec

For the first error, I think this line:

Code:
       ch = cin.get();
    }

actually ends the first while loop, which means this line:

Code:
ch = cin.get();
    } //Ends the first loop

Ends the boss function. Which means this line:

Code:
} //Ends the boss function

Actually does not end anything (thus needed a declaration ie another'{' symbol to make it mean something). I'm not 100% on this though.

Edit: for the second error try substituting the system line with this:

Code:
system("pause");
 

gosox333

Member
Hm, I tried putting the semicolon in after the (pause) like you said, but now it's giving me an additional "unqualified id before 'return'" error.

Thanks a lot for helping, by the way.
 

Bruiserk

Member
Whoops, while I edited the photo out I also slipped a more recent copy of the code into my post. The most recent one is different from the one you already looked at. My bad.

Thanks a lot for responding though. That's awesome.

So are the errors fixed?

edit: Just realized that the second error would be caused by system("pause") not being called by the main() function because of the first error I described. If you fix the first error and make sure to put system("pause") in the main function it should be fine.

Essentially this is what your code should look like:

Code:
#include <iomanip>
#include <iostream>
#include <ctype.h>

using namespace std;

int isDigit(char ch); //Function 1
int isUpper(char ch); //Function 2
int isLower(char ch); //Function 3
int isAlpha(char ch); //Function 4

int main() //The boss function
{
    //Displays a title for the calculator
    cout << "\n===============================================================\n" << endl
         << "    ~  Welcome to Purple Prose Press Payment Calculator!  ~" << endl
         << "\n===============================================================\n" << endl
         << "   - Enter characters to calculate.\n" << endl
         << "   - Place an ! at the beginning of the line to quit.\n" << endl
         << "---------------------------------------------------------------\n" << endl;
         
    char ch;
    //Delcares variables
    int numDig, numUpp, numLow, numAlp, totLow, totDig, totUpp, totAlp, totCha;
    
    totDig = totUpp = totAlp = totLow = 0;
    
    ch = cin.get();
    
    while (ch != '!')
    {//Starts the first loop
         numDig = numUpp = numLow = numAlp = 0;
		  
          if (isUpper(ch)) //Refers function 2
		  	  numUpp++;
			   
          if (isLower(ch)) //Refers function 3
              numLow++;
          
          if (isDigit(ch)) //Refers function 1
              numDig++;
          
		  if (isAlpha(ch))
		  	  numAlp++;    //Refers function 4
          
          ch = cin.get();
    
    //The += will add the individual sets if values and adds them up for the final info display
    totDig += numDig;
    totUpp += numUpp;
    totLow += numLow;
    totCha = numDig + numUpp + numLow;
    
    //These cout statements will display the values for the intial lines of characters
    cout << "   Upper case letters: \t\t\t" << numUpp << endl 
         << "   Lower case letters: \t\t\t" << numLow << endl
         << "   Digits: \t\t\t\t" << numDig << endl
		 << "   Characters: \t\t\t\t\t" << totCha << endl 
         << "\n---------------------------------------------------------------\n" << endl;
    ch = cin.get();


    } //Ends the first loop

    system ("pause")
    return 0;

} //ends the main boss function
    


int isDigit(char ch)
{
   if ((int)ch >= 48 && (int)ch <= 57)
      return 1;
   else
      return 0;
}

int isUpper(char ch)
{
   if ((int)ch >= 65 && (int)ch <= 90)
      return 1;
   else
      return 0;
}

int isLower(char ch)
{
   if ((int)ch >= 97 && (int)ch <= 122)
      return 1;
   else
      return 0;
}


int isAlpha(char ch)
{
	if ((int)ch >= 97 && (int)ch <= 27 || int(ch) >= 65 && int(ch) <= 90)
		return 1
	else
		return 0;
}
 

gosox333

Member
So are the errors fixed?

edit: Just realized that the second error would be caused by system("pause") not being called by the main() function because of the first error I described. If you fix the first error and make sure to put system("pause") in the main function it should be fine.

Essentially this is what your code should look like:

Code:

Alright, now that's an improvement. I'm getting an error for the int isAlpha function, but that's it.

Thank you so much.
 
Code:
int isAlpha(char ch)
{
	if ((int)ch >= 97 && (int)ch <= 27 || (int)ch >= 65 && (int)ch <= 90)
		return 1
	else
		return 0;
}

You type casted the parameter wrong. You had it like this: int(ch)
 

gosox333

Member
Code:
int isAlpha(char ch)
{
	if ((int)ch >= 97 && (int)ch <= 27 || (int)ch >= 65 && (int)ch <= 90)
		return 1
	else
		return 0;
}

You type casted the parameter wrong. You had it like this: int(ch)

Oh god, that's so fucking stupid....

BUT IT COMPILES. Thanks you jesus. And thank you, of course.
 
Its not stupid. Its part of learning. Everyone in here has made similar mistakes.

Who taught you to return ints instead of bools by the way? Its bugging the hell out of me.
 

Bruiserk

Member
Your code taught me something I didn't know.

I wasn't sure why you saying:

Code:
(int) ch

I guess that tells the program to look at the ch character as if it is an integer value?
 

gosox333

Member
Your code taught me something I didn't know.

I wasn't sure why you saying:

Code:
(int) ch

I guess that tells the program to look at the ch character as if it is an integer value?

Yeah, I think it has to do with the "ch = cin.get()" they had us using for this. It has it's own set of rules that comes with it.
 

Enkidu

Member
Yeah, I think it has to do with the "ch = cin.get()" they had us using for this. It has it's own set of rules that comes with it.
It's just a type conversion. "ch = cin.get()" is the same thing as doing "cin>>ch". It just reads the input stream and interprets it as a char (since that's the variable you decided to put it in). Using "(int) ch" means that the char will be interpreted as an int. It is actually not really necessary in this example though, since for "ch > 50", ch would already be implicitly converted to an int for the comparison. For example this:
Code:
char ch = 'A' + 1
would result in ch being equal to 'B'. There are also existing functions to check if a char is uppercase/lowercase/digit etc. that you can use.
 

Slavik81

Member
Code:
int isAlpha(char ch)
{
	if ((int)ch >= 97 && (int)ch <= 27 || (int)ch >= 65 && (int)ch <= 90)
		return 1
	else
		return 0;
}

You type casted the parameter wrong. You had it like this: int(ch)

There's nothing wrong with int(ch). That's a valid type of cast. It was added to C++ so built-in types would act more like user types for the sake of template programming.

The real reason that bit wouldn't compile is because he missed the semi-colon at the end of 'return 1'.
 
My professor, I guess. She hasn't mentioned the bools at all. Is that an easier way of doing things?

She hasnt mentioned bools? How far through the course are you? I'd use bools if you need to evaluate a statement to being true or false.

I was using older code. He had already added the semi-colon with Bruiserk's help. It was causing a compile error using the constructor argument passing.
 
This question pertains to either Windows Server or Fedora

I don't know if this would be the best place to ask, but I too need help with coding, however, I'm not sure if what I'm trying to write can be wrote with C++ or not; I assume it can be though. Basically, my teacher is having us write a program that takes a text file that already has information in it, and once it's prompted through cmd, the program then is supposed to add users to the computer based on the information in the text file. The text file has 100 lines containing text that looks similar to this (without the " on either side.) for each unique user:
Josh:Smitha:05-12-1982:junior:100-10-1000:c

We are required to have three different groups: students, faculty, and staff. Each user is supposed to be added to said specific group depending on if their listed as a teacher, staff, or freshman, sophomore, junior, and/or senior. We need to have the username formatted to be the first letter of the first name and the whole last name, including the last 2 digits of the social at the end (ex. jsmitha00). The password is just the users 8 digit birthday.

So to be short, I basically need the program to format all the accounts with the style the previous example has, create passwords using the birthday, and be put into the specific groups. Also, at the end of the first account I provided there is a letter c, only the accounts with the letter c are to be added, but the ones with a letter q are not to be added.

Unfortunately this isn't a coding class and I don't know anything about coding, so I haven't even figured out where to start!... Shit, I don't even know if C++ is what I'm supposed to be using! I'm going to ask my teacher for help tomorrow but I don't see him actually telling me much, so I figured I'd ask my fellow gaffers for a bit of input beforehand. If what I said doesn't make sense please let me know and I'll try to explain it better. I just need whatever help someones willing to provide, this assignment is confusing the hell out of me.
 

Enkidu

Member
This question pertains to either Windows Server or Fedora

I don't know if this would be the best place to ask, but I too need help with coding, however, I'm not sure if what I'm trying to write can be wrote with C++ or not; I assume it can be though. Basically, my teacher is having us write a program that takes a text file that already has information in it, and once it's prompted through cmd, the program then is supposed to add users to the computer based on the information in the text file. The text file has 100 lines containing text that looks similar to this (without the " on either side.) for each unique user:


We are required to have three different groups: students, faculty, and staff. Each user is supposed to be added to said specific group depending on if their listed as a teacher, staff, or freshman, sophomore, junior, and/or senior. We need to have the username formatted to be the first letter of the first name and the whole last name, including the last 2 digits of the social at the end (ex. jsmitha00). The password is just the users 8 digit birthday.

So to be short, I basically need the program to format all the accounts with the style the previous example has, create passwords using the birthday, and be put into the specific groups. Also, at the end of the first account I provided there is a letter c, only the accounts with the letter c are to be added, but the ones with a letter q are not to be added.

Unfortunately this isn't a coding class and I don't know anything about coding, so I haven't even figured out where to start!... Shit, I don't even know if C++ is what I'm supposed to be using! I'm going to ask my teacher for help tomorrow but I don't see him actually telling me much, so I figured I'd ask my fellow gaffers for a bit of input beforehand. If what I said doesn't make sense please let me know and I'll try to explain it better. I just need whatever help someones willing to provide, this assignment is confusing the hell out of me.
C++ is more than capable of what you want to do. Have you got any experience at all in programming with C++? Anyway, I'll list some useful tips and see if you can figure it out yourself.

Assuming that the text file you are writing from shouldn't be hardcoded into the program, you can get the name like this:
Code:
int main(int argc, char* argv[]){
}

This way you can give parameters to the program when you start it. For example, if you run "testProgram.exe test.txt" that means argc will be equal to 2, since you gave 2 parameters. argv[0] will contain "testProgram.exe" and argv[1] will contain "test.txt". Now that you have the name of the file to read from, you can create an ifstream object.
A simple example on how to use it:
Code:
ifstream in("test.txt");
in.close();
in.open("test2.txt");
in.close();
The ifstream object is a stream and works pretty much like cin does. Note that it takes c-strings as input parameters, not string objects. argv[] will contain c-strings though so if you use that method that won't be a problem. You also need to see whether the file was successfully opened, a simple if case like this works great for that:
Code:
if(!in){
   //the file couldn't be opened, handle the error
}
To read from it you can use the regular >> operator however based on the formatting you described, I think getline would great here. Try something like this:
Code:
string line;
while(getline(in, line)){
   stringstream stream(line);
   string word;
   while(getline(stream, word, ":"){
   }
}
First you read a line from the file, and store it in line. The while case will keep doing this until there are no more lines to read from the file. Then you store that line in a stringstream (works the same as any other stream, like ifstream but works on a string instead of a file). You then use getline again but this time using ":" as the delimiter which means that it will stop everytime it reaches a ":" character and give you the string before that.

If you want to store the information on the computer, you can use an ofstream object, similar to how ifstream works. I assume you can figure out the string operaations needed to format the username/password etc. You also need to include some files to get access to the various streams but you should be able to figure that out with a bit of googling.
 

Slavik81

Member
Stick, that sort of thing would generally be done with a scripting language. C++ could do it, but it would be a lot more complicated. On Fedora you'll want Perl or something of that sort. On Windows, you probably want to look into PowerShell.
 
D

Deleted member 30609

Unconfirmed Member
How in the world are you in a class that asks you to do that if you have no prior programming experience? Surely it would have been a prerequisite?

I mean, don't panic, it's manageable. I'm just curious.
 

Slavik81

Member
What do people think about boost::lexical_cast and its use of exceptions to communicate failure? I pretty much never use exceptions, but I'm doing some text parsing and I'm suddenly seeing why they might be useful. Propagating errors up to where they need to be handled is driving me nuts, especially because there are a million and one ways in which a string may be invalid.

Or, really, the use of exceptions in general to communicate that the desired result cannot be extracted from a given string.
 
What do people think about boost::lexical_cast and its use of exceptions to communicate failure? I pretty much never use exceptions, but I'm doing some text parsing and I'm suddenly seeing why they might be useful. Propagating errors up to where they need to be handled is driving me nuts, especially because there are a million and one ways in which a string may be invalid.

I'm not a huge fan of exceptions, I mean they're ok sometimes, but more often than not the exception design is poor.

boost::lexical_cast is fairly convenient though, I have to admit.

Recently I've been working in an environment where we have to compile with exceptions disabled so I've gotten used to quite a lot of things that before I considered horrible and clunky. So now I don't mind the simple AtoI type call (although we have different calls for every type. AtoI32, AtoU32, AtoF32, etc).

Exceptions' biggest strength is also its biggest weakness: You have to handle every single error. Most of the time this just means putting a catch (const exception& e) in your code instead of splitting them out by exception type. Is there any particular reason this catch-all type approach doesn't work for you? I mean do you actually need to handle the failure differently depending on why the lexical_cast failed?
 

Slavik81

Member
I was just trying to use boost::lexical_cast as an example, really. I'm wondering if exceptions might help me simplify my interface, or if I'll face any significant performance penalties for their use.

I'm trying to parse coordinates and there are a few coordinate formats that I want to try before I decide the user has given me garbage. My interface now is looking something along the lines of:

Code:
class Parser {
   virtual bool tryToDecode(const QString& string, Coordinate& output) = 0;
};

I plan to have a few parsers to handle different types of coordinates, but I think this is a little ugly. I was thinking I might be able to do better if I used exceptions and simplified the interface.

Code:
class Parser {
   virtual Coordinate decode(const QString& string) = 0;
};

Then I could easily communicate failure easily from within my parsers, have a simpler interface, and perhaps include an error message that actually explains why it failed (useful for testing and debugging).

Given that I've never used exceptions before, I'm wondering if that's a reasonable use of them for improving my code. Or, alternatively, if you have other suggestions. My current interface works (I've completed the first parser), but could be better.
 
I was just trying to use boost::lexical_cast as an example, really. I'm wondering if exceptions might help me simplify my interface, or if I'll face any significant performance penalties for their use.

I'm trying to parse coordinates and there are a few coordinate formats that I want to try before I decide the user has given me garbage. My interface now is looking something along the lines of:

Code:
class Parser {
   virtual bool tryToDecode(const QString& string, Coordinate& output) = 0;
};

I plan to have a few parsers to handle different types of coordinates, but I think this is a little ugly. I was thinking I might be able to do better if I used exceptions and simplified the interface.

Code:
class Parser {
   virtual Coordinate decode(const QString& string) = 0;
};

Then I could easily communicate failure easily from within my parsers, have a simpler interface, and perhaps include an error message that actually explains why it failed (useful for testing and debugging).

Given that I've never used exceptions before, I'm wondering if that's a reasonable use of them for improving my code. Or, alternatively, if you have other suggestions. My current interface works (I've completed the first parser), but could be better.


If you take a look at other exception-aware code and/or APIs (for example, .NET framework), for certain types of operations there is very often a Try version as well as an exception throwing version. This isn't always appropriate, but in this particular case it might be worth considering. For example, what if your interface looked like this:


Code:
struct Parser 
{
   virtual bool TryParse(const QString& string, Coordinate& output) = 0;

   virtual void Parse(const QString& string, Coordinate& output)
   {
      //return void instead of Coordinate as a micro-optimization, if that matters to you
      if (!TryParse(string, output))
         throw new exception("Invalid number format.");
   }
};



As I do more and more things in C++, I'm also starting to appreciate the idea of not using classes and virtual functions for everything. There's obviously the performance hit associated with the indirect pointer reference, but usually that's negligible. For me it's just the amount of code I have to write define a new class, then keep some sort of data structure that holds pointers to your interface, then iterate over them.


A lot of times (and trust me, I'm guilty of this myself) it's just a simple case of over-engineering. If you've only got 3-4 different types of Parse functions, just write them as separate functions overloaded on the output type. If you plan on adding support for tens or hundreds of different types of parsing strategies though, maybe wrapping it up in an interface like this and making many derived classes makes sense.


One thing I've come to appreciate is simply being able to look at piece of code and tell exactly what it does. When you put interfaces into the equation, you look at something like this:

Code:
bool success = false;
Coordinate c;
for (auto it = parsers.begin(); it != parsers.end() && !success; ++it)
    success = it->TryParse(string, c);

And you're like "shit, what does this do? How many different things is it going to check, and what are they?"

If there were a lot, that's the solution I would go with (not exceptions), but if there were only a couple, I'd probably do something like:

Code:
bool success = false;
Coordinate c;

success = success || ParseStrategy1(string, c);
success = success || ParseStrategy2(string, c);
success = success || ParseStrategy3(string, c);
success = success || ParseStrategy4(string, c);

Note that this short-circuits, so everything evaluates to a no-op as soon as the first one succeeds.

Here you get the full picture of what's going on just at a glance. It also means you have 4 highly generic functions that you could use as an argument to some other generic function which takes a function pointer (or function object rather)

Code:
DoSomething(input, output, ParseStrategy2);

if you so desire

Plus, your exception-throwing Parse function (if you opt for one) now becomes:

Code:
template<class A>
void Parse(const string& string, A& output)
{
    if (!TryParse(string, output))
        throw exception("Error parsing input");
}

And works for literally everything, although you could always specialize it if you wanted customized error messages for specific types.

TL;DR - I wouldn't use exceptions there unless you really, really wanted to convey specific causes of parse failures to the user, but that's just me.
 
Two pieces worth reading, first the classic wtf exceptions essay from yore:

http://ptgmedia.pearsoncmg.com/images/020163371x/supplements/Exception_Handling_Article.html

The canonical rebuttal:

http://www.boost.org/community/exception_safety.html

That said, it depends largely on the precedent of the environment in which you're programming since something like exception handling is generally a global framework state--it's either required or forbidden, usually the latter.

cpp_is_king sounds like he's going through the 12 stages of c++ grief. He'll be iso_c99_is_king before you know it :).
 

usea

Member
I haven't really seen any good arguments for avoiding exceptions in C++, but I'm also no expert and I realize C++ is kind of its own beast.

Coming from the .NET world, coding without exceptions seems like madness to me. Returning error codes is like, a huge violation of coding style and convention. The exception safety article on the boost site linked above makes 100% sense to me.

I also agree that you should go with whatever is standard in your code base. If this is a project only you will be working on, go with whichever you prefer. Personally, this version makes much more sense to me:
Code:
Coordinate decode(const QString& string)

I have no idea why anybody would use this:
Code:
void Parse(const QString& string, Coordinate& output)
Why return void and take an output parameter? That seems insane to me. Again, I recognize this isn't really my domain. Not asserting I'm right or anything.
 
Two pieces worth reading, first the classic wtf exceptions essay from yore:

http://ptgmedia.pearsoncmg.com/images/020163371x/supplements/Exception_Handling_Article.html

The canonical rebuttal:

http://www.boost.org/community/exception_safety.html

That said, it depends largely on the precedent of the environment in which you're programming since something like exception handling is generally a global framework state--it's either required or forbidden, usually the latter.

cpp_is_king sounds like he's going through the 12 stages of c++ grief. He'll be iso_c99_is_king before you know it :).

Haha. To be fair, c++ will always be the king of my heart :)

It takes a long time to really appreciate all the power it has though, and even longer to understand when that power hurts more than it helps.

When i interview people i like to see how modest people are in their use of language features. If you get someone who is just bad then you can bring them in at a low pay grade. But when you get someone who technically knows the language inside and out and is gung ho about doing things as object oriented, or generic as possible its often a sign that they're in the most dangerous time of their careers - when they know enough to do damage, but havent yet done enough damage to realize it yet.

I dont blame them really, you cant really be good until youve gone through that phase :). But its tough
 
I haven't really seen any good arguments for avoiding exceptions in C++, but I'm also no expert and I realize C++ is kind of its own beast.

Coming from the .NET world, coding without exceptions seems like madness to me. Returning error codes is like, a huge violation of coding style and convention. The exception safety article on the boost site linked above makes 100% sense to me.

I also agree that you should go with whatever is standard in your code base. If this is a project only you will be working on, go with whichever you prefer. Personally, this version makes much more sense to me:
Code:
Coordinate decode(const QString& string)

I have no idea why anybody would use this:
Code:
void Parse(const QString& string, Coordinate& output)
Why return void and take an output parameter? That seems insane to me. Again, I recognize this isn't really my domain. Not asserting I'm right or anything.

In this particular case, its probably not a huge deal. I did mention in a comment that it was a micro optimization.

By returning by value, it creates an additional temporary and additionally returns it through the stack. For classes with non trivial copy constructors or assignment operators, or where sizeof(C) is large, this is often inefficient.

Obviously the caller is going have to allocate his own copy anyway, so this way it involves zero copying at the expense of slightly less pleasant syntax.

In a purely generic interface though this is the only way to go because the output type can be completely arbitrary and you dont want your library to behave awfully with certain types
 

Lathentar

Looking for Pants
If he's programming in C#, the return type is a pointer and it is harmless to return that. Probably where a lot of the confusion comes from.

In C++ you need to use non-const reference parameters all the time. No way would you want to ever return a container class by value.
 

Slavik81

Member
If he's programming in C#, the return type is a pointer and it is harmless to return that. Probably where a lot of the confusion comes from.

In C++ you need to use non-const reference parameters all the time. No way would you want to ever return a container class by value.

I tend not have have that problem because Qt's containers are implicitly shared. They're all copy-on-write. Both output variables and exceptions are things I rarely deal with due to the libraries I use.
 

Lathentar

Looking for Pants
I tend not have have that problem because Qt's containers are implicitly shared. They're all copy-on-write. Both output variables and exceptions are things I rarely deal with due to the libraries I use.

I was referencing usea because he mentioned he works in .NET.

If you start working with the stl you'll start to use output variables more often when you start passing around/constructing containers.
 

Slavik81

Member
Sorry, I didn't mean to imply anything with that. I just wanted to expand a bit on what you said.

STL is certainly a different style entirely. It's almost strange how two programs can both be C++ and do things completely differently. There's a few different C++ 'worlds'.
 
How in the world are you in a class that asks you to do that if you have no prior programming experience? Surely it would have been a prerequisite?

I mean, don't panic, it's manageable. I'm just curious.

Thanks for the info guys, but luckily my teacher said he'd find some other project for me to do. I was stressing that damn assignment like no other.

And Rez, the class is Applied Centric Computing or basically learning about servers, domains, and other things of that manner. They are prerequisites to the class, but none that involve learning how to code. Maybe because it's a 4000 level computer course he assumed that most of us had coding experience or something? Hell I'm not really sure, I can't complain though because most teachers aren't as forgiving as he is and would have made me do the assignment like everyone else.

That's not to say that I wouldn't mind learning some programming though. I was just led to believe that most companies had their programs created by software developers either in or out of the company, but seems like it'd be best for me to learn some programming for cases like this. Would that program I asked about be considered pretty simple? It doesn't seem like it'd be too hard to create if I just knew a language.
 

Lathentar

Looking for Pants
Sorry, I didn't mean to imply anything with that. I just wanted to expand a bit on what you said.

STL is certainly a different style entirely. It's almost strange how two programs can both be C++ and do things completely differently. There's a few different C++ 'worlds'.

Yeah, you can certainly have a very very wide range of perfectly legitimate styles in C++. I've been slowly moving my style over to using far more non-member functions in namespace (global and anonymous). I started moving this direction after reading: http://drdobbs.com/184401197

Previously, I would have almost all of my functionality in classes. However, slow began moving as many functions as I could to namespaces. For private functions, I've tried to make them anonymous functions in the cpp. A change to the signature of these functions no longer requires a recompilation of all the files that include the header.
 
Yeah, you can certainly have a very very wide range of perfectly legitimate styles in C++. I've been slowly moving my style over to using far more non-member functions in namespace (global and anonymous). I started moving this direction after reading: http://drdobbs.com/184401197

Previously, I would have almost all of my functionality in classes. However, slow began moving as many functions as I could to namespaces. For private functions, I've tried to make them anonymous functions in the cpp. A change to the signature of these functions no longer requires a recompilation of all the files that include the header.

That's definitely useful, especially for large projects, but how do you deal with accessing private member variables?
 

usea

Member
That's definitely useful, especially for large projects, but how do you deal with accessing private member variables?
Function that must access private member variables are not the ones Meyers is referring to. He's only talking about functions that could be equally implemented as non-freiend, non-member functions (ie: don't depend on private implementation).

I don't completely buy all his points. Mostly because his definition of Degrees of Encapsulation is wrong to me.
This leads to a reasonable approach to evaluating the relative encapsulations of two implementations: if changing one might lead to more broken code than would the corresponding change to the other, the former is less encapsulated than the latter.
There are different degrees of broken code. Changing the name of a function from ApplyForce() to ApplyForces() has a far less severe impact as changing the way users interact with your class entirely. Additionally, the way he seems to define a "corresponding change" between his two examples seems flawed as well.

We've now seen that a reasonable way to gauge the amount of encapsulation in a class is to count the number of functions that might be broken if the class's implementation changes. That being the case, it becomes clear that a class with n member functions is more encapsulated than a class with n+1 member functions.
I don't get this either. If a function could just as easily be moved to a non-member, non-friend function, then it's also a function that would NOT be broken when your class's private implementation changes. And if it would be broken, it would be just as broken as some global or namespaced function as it would in your class. Encapsulation as a whole would not be decreased, only the encapsulation that could be blamed on your class directly.

If I understand his main point correctly, he's saying that since encapsulation relates directly to how changes in your class impact user code, you should move functions out of the class when possible/reasonable. Doing this increases your class's encapsulation because when that function changes, it's not technically part of your class anymore so it's not your class's fault when it's a breaking change. The obvious error in this being that no program as a whole is improved in any way, only the measure on your class directly is improved. You've simply shifted the blame.

That said I think Effective C++ is one of the best books I own and clearly Scott Meyers knows about a million times more than me about c++ and programming in general.

I suspect that I must not understand his point fully since I disagree with it.
 
Function that must access private member variables are not the ones Meyers is referring to. He's only talking about functions that could be equally implemented as non-freiend, non-member functions (ie: don't depend on private implementation).

I don't completely buy all his points. Mostly because his definition of Degrees of Encapsulation is wrong to me.
There are different degrees of broken code. Changing the name of a function from ApplyForce() to ApplyForces() has a far less severe impact as changing the way users interact with your class entirely.

I don't have time right now to read the article in full detail, but just going off of the short quote you mentioned there, I think I kind of agree with what he's saying. But I also agree with what you're saying. So, why the difference?

Moving a function from a class implementation to a non-member global function in an anonymous namespace does not necessarily imply that you must change the way someone uses your class. For example, the function you're moving could be private. It's certainly possible that moving a function out of a class and into a global non-member function would not affect any single user of the class anywhere.


Additionally, the way he seems to define a "corresponding change" between his two examples seems flawed as well.

I don't get this either. If a function could just as easily be moved to a non-member, non-friend function, then it's also a function that would NOT be broken when your class's private implementation changes. And if it would be broken, it would be just as broken as some global or namespaced function as it would in your class. Encapsulation as a whole would not be decreased, only the encapsulation that could be blamed on your class directly.

I think I kind of agree with you here, but there is still another advantage: compilation speed. C++ has a nasty habit of having a single header file change require recompilation and re-linking of a MASSIVE number of files, even when you only change something simple. So moving to a non-member non-friend function in a cpp file does have the advantage that you are now free to change the implementation without triggering a recompilation of everything. On large projects, even just a few hundred thousand lines, this can be extremely aggravating. Changing one function take an int64 instead of a uint64 should not take 5 minutes to recompile
 

usea

Member
Yeah. I agree that it can be a good idea to move those functions (taking a lot of other factors in interface design into account), I just don't think his reasoning is very good.

Edit: Perhaps when he says you should move a function out of a class, he really means you should just change the function to act independently (take parameters rather than directly operate on class members). I can see how that would increase encapsulation by his definition, but you don't have to remove the function from the class to do that.
 
Since we're talking about basically the pros and cons of the pimpl idiom, I might as well mention as an aside that there's an interesting way to implement the pimpl idiom in a way that avoids their biggest problem: the dynamic pointer indirection. Of course, nothing in life is free, the tradeoff should be immediately apparent.


Code:
//foo.h

class Foo
{
public:
     enum {IMPL_SIZE = 32};

     Foo();

     void PublicInterfaceMethod1();
     void PublicInterfaceMethod2();
     void PublicInterfaceMethod3();

private:
     uint64_t mImpl[IMPL_SIZE / sizeof(uint64_t)];
};


//foo.cpp
class FooImpl
{
     uint64_t mMember1;
     uint64_t mMember2;
     uint64_t mMember3;
     uint64_t mMember4;
};


Foo::Foo()
{
    static_assert(sizeof(FooImpl) == sizeof(Foo::mImpl));
    new(mImpl) FooImpl();
}


void Foo::PublicInterfaceMethod1()
{
    ((FooImpl*)mImpl)->PublicInterfaceMethod1();
}

void Foo::PublicInterfaceMethod2()
{
    ((FooImpl*)mImpl)->PublicInterfaceMethod2();
}

void Foo::PublicInterfaceMethod3()
{
    ((FooImpl*)mImpl)->PublicInterfaceMethod3();
}

This is the ultimate solution to minimize recompilation, but it's certainly a little unsightly.
 

Enkidu

Member
Thanks for the info guys, but luckily my teacher said he'd find some other project for me to do. I was stressing that damn assignment like no other.

And Rez, the class is Applied Centric Computing or basically learning about servers, domains, and other things of that manner. They are prerequisites to the class, but none that involve learning how to code. Maybe because it's a 4000 level computer course he assumed that most of us had coding experience or something? Hell I'm not really sure, I can't complain though because most teachers aren't as forgiving as he is and would have made me do the assignment like everyone else.

That's not to say that I wouldn't mind learning some programming though. I was just led to believe that most companies had their programs created by software developers either in or out of the company, but seems like it'd be best for me to learn some programming for cases like this. Would that program I asked about be considered pretty simple? It doesn't seem like it'd be too hard to create if I just knew a language.
What background do you have? For most technical fields it's probably a good idea to know some programming these days. Anyway, a program that does what you want would be quite simple, you would probably be able to do it without much problem after taking any sort of introductory programming course.
 

Lathentar

Looking for Pants
Since we're talking about basically the pros and cons of the pimpl idiom, I might as well mention as an aside that there's an interesting way to implement the pimpl idiom in a way that avoids their biggest problem: the dynamic pointer indirection. Of course, nothing in life is free, the tradeoff should be immediately apparent.
I always thought that the pimpl idiom takes things a bit far. Its a compensation for poor languages decisions.
 
I always thought that the pimpl idiom takes things a bit far. Its a compensation for poor languages decisions.

Indeed. In ISO C99 land our version of this is opaque interfaces for anything but the simplest of POD types:

Code:
typedef float32x2_t vec2_t;
typedef float32x3_t vec3_t;

typedef struct _vertex_t {
  vec3_t pos;
  vec2_t uv;
  vec3_t normal;
  uint32_t color;
} vertex_t;

typedef void* mesh_t;

mesh_t mesh_alloc( void );
void mesh_init( mesh_t mesh );
void mesh_fini( mesh_t mesh );
void mesh_free( mesh_t mesh );

size_t mesh_num_verts( mesh_t mesh );
const vertex_t* mesh_get_verts( mesh_t mesh );
/* etc. */

Although this is a contrived example (in game code we rarely care about this since we're focused on performance and delivering a specific game, not some abstract engine or library), it gets the idea across.
 

maharg

idspispopd
Indeed. In ISO C99 land our version of this is opaque interfaces for anything but the simplest of POD types:

Code:
typedef float32x2_t vec2_t;
typedef float32x3_t vec3_t;

typedef struct _vertex_t {
  vec3_t pos;
  vec2_t uv;
  vec3_t normal;
  uint32_t color;
} vertex_t;

typedef void* mesh_t;

mesh_t mesh_alloc( void );
void mesh_init( mesh_t mesh );
void mesh_fini( mesh_t mesh );
void mesh_free( mesh_t mesh );

size_t mesh_num_verts( mesh_t mesh );
const vertex_t* mesh_get_verts( mesh_t mesh );
/* etc. */

Although this is a contrived example (in game code we rarely care about this since we're focused on performance and delivering a specific game, not some abstract engine or library), it gets the idea across.

You've abstracted this a lot farther than you need to unless you're really intent on hiding implementation details from library users (like, say, win32 api handles). You could just use forward declarations and then not need to cast stuff back from void* all the time in your library code.

The reason you need to recompile everything in C++ because of a change in any method signature is because of overloading. I'm not sure it's really possible to have both overloading and a C-style ability to just use opaque forward declarations everywhere.
 

tokkun

Member
Yeah, you can certainly have a very very wide range of perfectly legitimate styles in C++. I've been slowly moving my style over to using far more non-member functions in namespace (global and anonymous). I started moving this direction after reading: http://drdobbs.com/184401197

Isn't there a pretty basic logical error in his justification of why the non-member function would be better?

If the function could be implemented as a member function that only accesses the public interfaces, then it would not break if private data were changed (provided the programmer actually uses only the public interfaces). In that case it would have neutral effect on the level of encapsulation.

You might say that there is no purpose to include it in the class if it uses only the public interfaces, but it might still be included in the class for the purpose of code organization or maintaining the Object paradigm.
 
Isn't there a pretty basic logical error in his justification of why the non-member function would be better?

If the function could be implemented as a member function that only accesses the public interfaces, then it would not break if private data were changed (provided the programmer actually uses only the public interfaces). In that case it would have neutral effect on the level of encapsulation.

You might say that there is no purpose to include it in the class if it uses only the public interfaces, but it might still be included in the class for the purpose of code organization or maintaining the Object paradigm.

I don't think he's necessarily saying that you should simply delete N functions from your class and copy/paste those N functions into a CPP file with only a few minor changes to make the pointer indirection explicit (since this no longer exists)

Often times in order to achieve what he's suggesting, it involves a little bit of refactor to get your functions to STOP accessing private member data where it's not necessary, or splitting logic into other functions etc.
 

Bruiserk

Member
Alright, a little context before I type my problem. For this problem we have to calculate how many times we have to reverse the first m digits in the vector, where m is the first integer in the permutation. For example, if:

v = [3, 4, 5, 1, 2]

The first number is 3, so we reverse the first 3 digits:

v = [5, 4, 3, 1, 2]

Then we reverse the first 5 digits:

v = [2, 1, 3, 4, 5]

Now reverse the first 2:

v = [1, 2, 3, 4, 5]

Now 1 is in the first place, this ends the game. The score for this game is the number of times we did a reversal, so that would be three for this example. Can anyone offer any help with the issue I'm having here?

An intermediate step is to make a function that calculates the score of a given permuation, this is what my preliminary code looks like:

Code:
// Pre: is_permutation(v)
// Post: Returns the number of reversals needed to make v[0] == 1
//       if the reversal game were played on v.
// Note: If ``v[0] == 1`` initially, then ``score(v)`` returns 0.
int score(const vector<int>& v) {
  assert(is_permutation(v));
  int score = 0;
  vector<int> v_test = v;
  while(v_test[0] != 1) {
    if(v_test[0] == v_test.size()) {
      reverse(v_test.begin(), v_test.end());
      ++score;
    }
    else {
      reverse(v_test.begin(), v_test.begin()+v[0]);
      ++score;
    } 
  }
  return score;
  
}

For a vector v = [3, 1, 2] it enters an infinite loop and I have no idea why. For every other permutation of [1, 2, 3] it works just fine. Can anyone offer any help?

EDIT: nvm. my TA helped me fix it. Had to do with:

reverse(v_test.begin(), v_test.begin()+v[0]);

Should be v_test[0]. I'll keep the question up for curiosity sake.
 
Status
Not open for further replies.
Top Bottom