mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

When your code grows larger, one book becomes essential: C++ Coding Standards, by Sutter and Alexandrescu. And probably reading through a few of the GotW website is also a good idea.

The Boost guidelines are also very good. And this article too.

Other than that, I have rarely seen any real good resources (online or not) that comprehensively treat the subject of error-handling (I think many traditional C++ programmers still have trouble committing too much to exception mechanisms and still rely on C-style error-codes for a lot of things, if not all).

But one thing is clear though, from all those who know what they are talking about, the best error-handling method is throwing and catching exceptions, no doubts about that. So, the starting point is understanding exceptions and learning how to use them effectively. Read the C++FAQ on exceptions, as a starter.

A few useful things:
ScopeGuards, Pragmatism, RAII, Copy-and-swap, Non-throwing swap.

Ancient Dragon commented: You always have great answers :) +36
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>i've seen in some sources that some classes have Getters and Setters even for public data members
Remember that a large amount of open-source software is designed like a steaming pile of dog... Don't consider everything you see as "good practice" or as if the design choices they made were good, justified or even planned at all. This is true of roughly all programming languages with equal proportions: the amount of very poorly written open-source code far exceeds the amount of well-written open-source code. It doesn't mean that it is not _usable_, it just means that you shouldn't derive too many programming guidelines from the open-source code that you see.

>>I don't know why would someone lose time for declaring functions for public data members
Did you consider that maybe this didn't come at once? Maybe it used to be private/protected and used via get/set in many other functions of the software, then somebody decided that he preferred the data members to be public (a stupid decision IMO, but possible). Also, maybe there used to be more complex behaviour in the get/set functions (like bound-checking or mutex-locking) which was taken out after some testing or performance assessment, but the get/set were left such that the rest of the software would not need refactoring. There are plenty of other reasons why this might have happened (amongst them: just that the author is stupid). Real-world programming involves a lot of little issues, often related to maintenance, that make real-world …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Is there a particular thing it does that makes the program slow/unstable?
No. It makes absolutely no difference in terms of performance, it is just a trick to get the compiler to do its job.

>>Why should I only do the forward-declarations as a last resort?
I wouldn't call forward-declarations a last resort (there are far worst things, like using a void* and doing casts later). There is nothing wrong with a forward-declaration, but it should be considered only after taking a close look at the design to see if it is necessary. The reason is simple. A forward-declaration is generally used to achieve inter-dependency between two classes, which is never desirable on a software design and maintainability stand-point, but it is not always avoidable. But if the inter-dependence can be avoid, it will lead to better design. You have experienced that yourself. You looked back at your design a found a better, less-coupled way of achieving the same task (with a bonus of efficiency). That's why I recommended rethinking your design first, because I was quite certain that you could find a solution that didn't involve this inter-dependency (most of the time, forward-declarations are avoidable via better design).

griswolf commented: Good points +1
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

This is called a circular referencing problem (Particle needs MapGrid, which needs Particle, which needs MapGrid, ... ad infinitum). Headers guards won't solve that problem. You need to either break the circular referencing through a (better) design of the software, or you can turn the circular referencing to a semi-circular referencing.

Options to restructure:
- Perhaps the functionality for which one of the classes needs the other could be implemented differently. Often, circular dependencies are an indication that the tasks are not properly split between the two classes. Take a second look at the functionality to see if it really makes the most sense to do it that way.
- Perhaps you simply need to define a base class for one of the two classes. If one of the classes uses the other in a simple non-intrusive manner, then, probably, you can put this simple interfaces as pure virtual functions of a base class. In this case, you have no more circular referencing. For example, MapGrid could depend on BaseParticle, and Particle could depend on both MapGrid and BaseParticle, i.e. no more circular dependency.

Breaking Circularity:
If the above options are not suitable for your application, you can break circular dependency via forward-declarations. Here is an example:

//in MapGrid.h
#include <windows.h>
//...
//do not include Particle.h

class Particle; //forward-declaration of class Particle (found in Particle.h)

class MapGrid {
  ///... uses Particle* or Particle& in the function prototypes or data members.
};

//in MapGrid.cpp
#include …
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The syntax is:

class Thing
{
    public:
    template <typename T>
    operator T(); //notice, no return type (it is implicit for conversion operators)
}

And it certainly is possible (at least it works on GCC). I'm not sure why you would want to do that, but you can.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

First of all, this is highly dependent on the capabilities that you want your plugin system to be able to handle. It can range from a very simple set of capabilities, leading to a fairly easy task to accomplish, to a very comprehensive set of capabilities, leading to a very very difficult task to accomplish.

Simplest case:
If all you want is for your plugin to be a DLL that provides a certain set of functions, then it is pretty easy to do. For example, imagine that the plugin's sole purpose is to load a sound file and play it. You could define a certain number of standard functions (like LoadAudioFile(), PlayAudio(), PauseAudio(), StopAudio(), etc.). Then, in your application, given a DLL, you have to load it dynamically (with LoadLibrary() (windows) or dlopen() (linux)), get function pointers for each of the standard functions (with GetProcAddress() (windows) or dlsym() (linux)), then, if all the pointers are non-NULL (i.e. they all exist in the DLL, or at least, a non-optional subset of them), you can use those function pointers to execute the functionality from the DLL, and finally, when done with it, you free the DLL (with FreeLibrary() (windows) or dlclose() (linux)). And that's it, pretty much.

Complex case:
If you want your plugin to provide an extensible set of functionalities and possibly an extensible set of classes, then it becomes much harder. I have done …

jonsca commented: Nice post. +8
gerard4143 commented: Nice break down +5
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

First, the way that you can test whether you have run out of memory in the program is to check that the pointer you get from malloc is not NULL. This pointer will be NULL if you are out-of-memory. This is also why you get the error of dereferencing a NULL pointer (access violation).

Second, memory issues are hard to solve with limited knowledge and experience, but they are even more problematic when using C-style arrays (and with malloc). You should definitely switch to std::vector storage instead. And for you matrices, store them in one contiguous memory block (not array of arrays, but one big array). With this changes, your constructor of Matrix2D would be as such:

// assuming that elements was declared as: std::vector<double> elements;

Matrix2D::Matrix2D(int n_rows, int n_columns)
{
	r = n_rows;
	c = n_columns;

	elements.resize(r * c);
        
        for(int i=0; i < r; ++i)
	{
		for(int j=0; j < c; ++j)
		{
			elements[i * c + j] = 0.0; //map the indices as so.
		}
	}
}

With the above changes, you won't need to worry about clean-up (deallocating memory), because the std::vector object will take care of that. Similarly, the copy-constructor and assignment operator are also automatic deep-copies and won't leak.

Finally, if your matrices are large, you really need to make sure that copying is minimal (i.e. don't copy matrices around all the time). Your "transpose" function is extremely wasteful (at least if the compiler isn't really good at optimizing, which it is …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The << and >> operator do have higher precedence than the bitand & operator, see this table.

However, I would not recommend that you rely on operator precedence in that kind of fashion. If you need, absolutely need, to use a #define, then wrap everything with parentheses and avoid the problem:

#define FLAG_FAST         (1 << 0)
#define FLAG_VISIBILE     (1 << 1)
#define FLAG_BIG          (1 << 2)

In this case, however, you are defining those flags in a very impractical fashion. This is the more "usual" way, using hexadecimal numbers:

#define FLAG_FAST         0x00
#define FLAG_VISIBILE     0x01
#define FLAG_BIG          0x02
#define FLAG_FOO          0x04
#define FLAT_BAR          0x08
//...

But when I say that the above is "usual", I really mean that it is commonly found in C libraries or APIs, but not in C++ code. In C++, there are several alternatives that are safer and better. One is to use a const global variable (or static const data member of a class):

const unsigned int FLAG_FAST     = 0x00;
const unsigned int FLAG_VISIBILE = 0x01;
const unsigned int FLAG_BIG      = 0x02;

Another popular solution is to use an enum:

enum MyFlags {
  FLAG_FAST     = 0x00,
  FLAG_VISIBILE = 0x01,
  FLAG_BIG      = 0x02
};

And usually, the enums are nested in the class or namespace they are used in or for.

MACROs in C++ have their place for very special purposes that cannot be achieved by any other means and do require a simple text-replace preprocessing. But defining …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

What you need is basically a discriminated union (often called a variant type). This is just a union of an integer and a character along with a flag to tell which type is actually stored in the union. Here is a simple example:

class CharOrInt {
  private:
    union {
      char c;
      int i;
    } data;

    enum { char_data, int_data } data_type;

  public:
    explicit CharOrInt(char c) { data.c = c; data_type = char_data; };
    explicit CharOrInt(int i) { data.i = i; data_type = int_data; };

    CharOrInt& operator=(char c) { data.c = c; data_type = char_data; };
    CharOrInt& operator=(int i) { data.i = i; data_type = int_data; };

    bool operator <(const CharOrInt& rhs) const {
      if(data_type == char_data) {
        if(rhs.data_type == char_data) 
          return data.c < rhs.data.c;
        else
          return ((data.c < '0') || ((data.c <= '9') && (data.c - '0' < rhs.data.i)));
      } else {
        if(rhs.data_type == char_data) 
          return ((rhs.data.c > '9') || ((rhs.data.c >= '0') && (rhs.data.c - '0' > data.i)));
        else
          return data.i < rhs.data.i;
      };
    };
};

You can basically used the above data type instead of the int type in your sorting algorithm and it should work as you want. If not, just modify it to suit your needs.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>I guess I could use my singleton as a master class from which all other classes would be derived
NO! Don't do that. Really, don't!

>>maybe I could use some friend functions.
Hissh, probably wouldn't do that either, sounds messy and unnecessary.

>>how can the member functions of my set of classes access the float value they need within my singleton.
If it makes sense for different part of the software to modify the float value at will, then provide a function to do that. In other words, have both a GetValue() and SetValue(float NewValue) functions defined in your singleton.

>>I am defining my singleton within main()
That's not the way to do it. You need a separate header for the singleton's declaration and a separate cpp file for the singleton's implementation (don't put any of the two in your main.cpp file, I mean, for real, it completely defeats the purpose of the singleton).

All the classes that need to access (public) members (data or functions) of the singleton should include the singleton's header and use the static member function to get the instance of the singleton on which to operate.

I don't see how this could cause any problems, as long as the public functions of your singleton are sufficient for the purpose that any classes could make of it. If your singleton doesn't provide enough access to its members, add access to them, that's all (but don't abuse, because …

VernonDozier commented: As always, good post. +13
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The downside of using extern constants is that they will require linking. Basically, the header tells the code that you are compiling that when you link your application, there will be definitions for those constants available to the linker to find. So the compiler annotates those constants as having to be looked up at link-time (with associated external symbol). Also, when compiling the source file in which the constants are defined, it creates a published symbol for each constant.

The disadvantage is obviously that you get "larger" static libraries (or shared libraries) because they need to have more external symbols. This means "longer" times for linking the compiled code. Also, if compiled into shared libraries (.so or .dll), it will result in "longer" time for loading up the program. But, of course, if the number of constants is small, it really won't be that much longer (probably not noticeable).

The advantage is that you can change the value of those constants in the source file without having to recompile all the code that uses these constants (you only need to re-link them, if compiled in static libraries, and you don't need to do anything more if compiled in shared libraries).

Generally, I would recommend that you use extern constants only if you plan on changing their values fairly often. For constants that are really "constants" like PI/2, there really is no point, just take out the "extern" keyword and define them in the header (as in your …

thekashyap commented: Good desc of the limits.. +5
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

"Time Complexities" is really just a measure of what running times you should expect as a function of the amount of data you are working on. It is not a precise measure (at least it rarely is), and can't really be "used". It's more like a measure of how good an algorithm is (often, compared to another algorithm or to how "difficult" the problem is).

For example, if I have an array that I want to fill with 0 values, then I would go through each element of the array and set it to 0. I don't really know how much time it takes to set one element to 0, but I know that it takes the same amount of time to set any one element or another to 0, in other words, the time for this operation is a constant, lets call it A. Then, since I will go through each of the N elements of the array, the time that it would take is A*N. But since I really don't know A (without doing performance tests on my computer), I just say that the operation is proportional to N, another way of saying it is that it is of the order of N, and hence, the big-O notation O(N).

The point is that this measures how scalable an algorithm is. Since any problem is trivial if N is really small (i.e. if you have 5 elements to sort, it doesn't matter much what algorithm you use, …

vmanes commented: Good explanation +7
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Normally it is done as follows:

//in stack.h

#ifndef STACK_H
#define STACK_H

//include whatever you need.
#include <exception>

namespace my_code { //put your stuff in a namespace of your choosing.

struct stack_full_failure : public std::exception {
  const char* what() const throw() {
    return "Stack is full!";
  };
};

template <typename T>
class stack {
  //... your implementation of stack.

  void push(const T& NewElement) {
    if(numElements == stackSize)     //if the stack is full
      throw stack_full_failure;      //throw your exception.
    data[numElements++] = NewElement;//else, add the element to the stack.
  };
};

};

#endif

Whether the code is in the header file or in the cpp file doesn't really matter (I mean the "standard" guidelines still apply: don't put too much code in the header, don't break the clarity of the code, if stack is templated you pretty much have to put the code in the header, etc.).

The custom exception classes that you might want to define (like stack_full_failure in my example) are basically part of the interface of your class, so it makes sense that they would reside in the same header file.

Also, for a real library, it makes sense to document things well, for example with doxygen tags:

/**
 * This exception class is thrown when an operation that requires growing a 
 * stack's size cannot be performed because it exceeds the stack's maximum 
 * capacity.
 */
struct stack_full_failure : public std::exception {
  //...
};
/**
 * This class implements ...
 */
template <typename T>
class …
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

If you are going to use a singleton, do it correctly. The code that L7Sqr posted has two big flaws: before calling instance(), the pointer "only_copy" is not necessarily NULL, and thus, the test (!only_copy) is likely to be false even on the first use of instance(); second, there will be a different copy of "only_copy" in each translation unit (that might not be a concern to you right now, but better learn the proper way soon rather than later).

The recommended way of implementing a singleton is as follows:

//in Timer.h
class Timer {
   int x;
   Timer () : x(0) {} // Private
   Timer(const Timer&); //make the Timer class non-copyable (such that another instance cannot be created)
   Timer& operator=(const Timer&); //make non-assignable for the same reason.
public:
   static Timer& instance (); //return the instance by reference.
   int getX () { return x; }
};

//in Timer.cpp

Timer& Timer::instance() {
  static Timer only_copy; //static-scoped instance (initialized only once).
  return only_copy;       //return by reference.
};

Later, you can use it as:

Timer& t = Timer::instance();
  int x = t.getX();

Putting the "only_copy" instance as a static variable in the cpp file, you guarantee uniqueness across translation units (and modules), and you guarantee that it will be initialized at least once and exactly once.

L7Sqr commented: Thank you for the corrections. +1
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

First of all, the code that you posted has several errors. First, the array "b" is not a dynamically allocated array, it is a fixed-size array (deduced from the number of elements between curly braces) that resides on the stack frame of the function. This means that after you return from the function, that array will no longer exist and the pointer that you have provided to the caller will be invalid. Second, the memory that is allocated by "a = new int;" is only big enough for 1 integer value. Third, when you do "a=b;" you are just making the pointer a to point to the same location as b, which is the start of the static array that will disappear when you return from the function. Finally, this function has a memory leak because the memory that is allocated with "a = new int;" is never deleted and can never be (it is unreachable memory).

Most importantly, in C++, it's considered very bad practice to allocate memory inside a function and give away a pointer to that memory as a return value, expecting the caller to know how to delete that memory. This might be OK in Java (because Java's GC holds your hand like a little baby), but that's just an undesirable side-effect of garbage collection (it makes people forget that in any language, garbage collected or not, it's poor coding practice to do this).

The usual solution in C++ either something like this:


       
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Learning a programming language involves two things: the syntax and the programming paradigm. The syntax includes all the little rules like = is an assignment and == is a comparison (in C/C++ and related languages), operator priorities, keywords, declaration syntax, etc. These are usually trivial to learn or look-up when in doubt. But, surely, some languages have a more cryptic syntax than others (and that is usually quite subjective). C++ is generally pretty straight-forward for syntax (although there are a few syntax oddities in C++, like trigraphs, the declaration-over-statement rule, or function pointer type declarations), and many languages are strongly influenced by C++'s syntax (so C++ is a good syntax to know, and know well).

Learning the programming paradigm is far less trivial. As opposed to syntax which is about translating your mental image of a program/algorithm into working code, the programming paradigm is about how you construct that mental image of the software, i.e. it's the mindset with which you tackle a problem. C++ is very good for this because it is already a multiple paradigm languages (native support for functional, procedural, object-oriented, generic, and meta-programming paradigms, and supports almost any other paradigm via an appropriate Domain Specific Embedded Language (DSEL) library).

So, I would say that "to master all languages" really is not that important. It is really much more important to master all programming paradigms and coding styles, because it is the way you choose to solve a problem, based on the most appropriate paradigm …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>By the way I am using turbo compiler 3.0
OMG! That's a 20 year old compiler! This is archaic! Please consider switching to something newer. With that compiler, I'm doubting you could even compile whatever code you would like to compile, "within a C++ program" or not (whatever that means, as rubberman has pointed out). Consider maybe MinGW GCC, it is free and always reasonably up-to-date.

jonsca commented: This always bears repeating. +7
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

I'm guessing the point of this program is not to use an integer to store the values and then add them to get the result. Right? Because in that case, the program would just be:

#include <iostream>
using namespace std;

int main() {
  int a,b;
  cout << "\nEnter first number: "; cin >> a; cin.ignore();
  cout << "\nEnter second number: "; cin >> b; cin.ignore();
  cout << "\nThe result comes to: " << (a + b) << endl;
  return 0;
};

Now, are you required to use char arrays? If you are, I find it a bit sadistic on the teacher's part. In C++, we use std::string for things like that because it's so much better.

If you are forced to use char arrays, there are a few things to know. First, don't abuse the strlen() function. This function loops through the characters until it finds a null-character. It's just a waste to compute this more than once for a string. Compute it and store it in a local variable, don't recompute it over and over like you do on lines 52 to 66 for example.

Second, don't make functions that allocate a char array and then output a pointer to it. That's just a recipe for disaster. Preallocate the "output" string and pass the pointer as a parameter (like all str functions do (strlen, strcpy, strcmp, substr, etc.)).

Third, anything you allocate needs to be deallocated (i.e. every new-statement has to be matched with a …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

I think the answers so far are very good, but I could have a few things to add, because I love answering good questions like this.

>>Memory and CPU efficiencies are important

Then don't use the function at(i) like you do at line 16 and 36. The at function includes bound-checking which is a waste when you are just looping through. That's just a small remark. Use the [] indexing operator or iterators instead.

>>1. Memory leak. Does the order in which the class destructors are called ensure that there is no memory leak? When the collection destructor is called, I needed to "delete sets->at(i)" to deallocate the Set objects allocated elsewhere, but does the Set destructor get called, or does a memory leak result?

To answer the question: You did it correctly in the sense that memory won't be leaking, as far as I can see. The destructors for the sets will be called and so will the default destructor of the segments. If you want to check for memory leaks, run your program in Valgrind (I would suggest you run it on a smaller amount of "test" data, both because if you do have a leak, you don't want to have massive leaks reported, and because valgrind is a virtual machine that is slow because it does a lot of bookkeeping to allow you to trace back the leaks, post mortem). For memory issues Valgrind is the tool to use.

On the grander …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Pretty much in my order of preference (note that it might not be yours):

1. Code.Blocks (free, with MinGW GCC)
1. Visual Studio 2010 (or Visual C++ Express (free))
2. Eclipse C++ (free, but you need to install and configure your compiler of choice yourself)

Things to look for that I find useful is fast background parsing that can highlight the code (i.e. recognize variable names and types, and color them such that you see right away if you made a typo by checking if it got highlighted correctly), code completion (i.e. you type the start of a variable name or type and it completes it for you by scanning (efficiently) your code-base), good support for external build systems (like cmake or makefiles), good debugging features, etc. Mostly, Code.Blocks and Visual Studio achieve this fairly well (I do find that Code.Blocks' code completion and background parsing is a bit slow though). I actually prefer, above all, KDevelop 4, because it scores the best on all the above criteria, but it's only for Linux.

As for compilers:
1. MinGW GCC 4.5 (or newer) (there is a good deal of improvement from 4.4 to 4.5, and 4.6)
2. Comeau (not free, but cheap, great standard compliance (better than any other compiler for this))
3. Intel Compiler Collection (ICC) (if you can afford it, it has great performance and great compliance, …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>What programs did you make after learning these things and can you recommend me what I should write with knowledge of these features?

Some of my early programs, while at your level, mostly revolved around 3D graphics (simple 2D/3D computer games, simple physics engines, collision detection algorithms, procedural generation of landscapes and other natural artifacts, particle systems, dynamics simulator and editor, etc.). The best project for you is the project YOU are most interested in (I'm a math junky so that drove the type of programs I played around with, and still work on today).

It's always difficult to keep yourself focused when you are doing programs as a hobby (not for money or a university degree, or both). To maximize your chances of not getting bored or burnt out, you should first make sure you have a good interest in the field (that drives the "impress yourself" reward-system), and second, try to pick a project that is very incremental and implement it incrementally so that you see new results every step of the way (it also eases the debugging/testing process a lot!). Another thing that can boost your focus and engage you more into the project is to do it with others, with friends and/or through an open-source team-project.

Following a level of knowledge in C++ that makes you feel confident enough to move from "textbook example" kind-of code towards a more concrete project, I think the natural next step is to learn to use other …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The * (star) that designates a pointer is linked to the type, not the variable name. That's why I prefer the convention int* ptr; instead of int *ptr; , just because it makes it more obvious that it is a variable of name "ptr" which is a pointer to an integer. In other words, the star qualifies the type, not the variable.

With this in mind, what is wrong with your implementation is that when you set the initial value of your static data member "m", you are putting the star in the wrong location (next to the name, not to the type). So here is the solution:

int* myclass::m = NULL;

That will make it compile, but there are definitely things that are wrong with your implementation, namely, you are dereferencing pointers that were never initialized to point anywhere (i.e. l and m).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You can think of it in terms of std::vector. This is a reasonable guess at how it is implemented (probably not actually uses a std::vector, but it is the basic example of a constant-amortized dynamic buffer):

//here, I'm just replacing the string with a vector of char to show how it is done:
std::istream& operator >>(std::istream& in, std::vector<char>& s) {
  char c;
  while ((in.get(c)) && (!isspace(c)))
    s.push_back(c);
  return in;
};

Since the dynamic array that is contained in std::vector is constant-amortized, the size will grow exponentially until it doesn't need to grow anymore. That is, IMO, the most likely implementation (or at least, a slightly more sophisticated version of that).

If you are talking about the buffer on the side of the IO stream, then that is a slightly different story. In that case, buffers are often implemented as rolling queues (i.e. you have a "fixed" size buffer with some index for the start (where the get pointer points to) and an index for the end, and basically, you make the start-ptr chase the end-ptr round and round the array, it is only if the end-ptr gains on the start-ptr that you need to allocate more memory).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

I don't think you could possibly find a book that talks about Lambda expressions in C++, because they are not even officially supported yet (but the new C++ standard will be there by the end of this year, at least, everyone is crossing their fingers for that).

From reading the list of chapters you posted, I think I would just recommend you get another book. Half of the book is about MFC, which is being phased out even in the Windows-only world (which is a world that is also shrinking rapidly). And only one chapter on the Standard Template Library! That can't be serious! But you should at least read that chapter before you let go of the book and go for a better one (which I can't recommend, cause I haven't learned through books and never read any other than the most advanced ones, I'm sure others will, or look at this thread).

If you have read through this book already and done enough hands on to get a good grip of the language (and I mean a lot!), then I would first recommend you go through all the C++FAQs. This is a good run-through of all the little intricacies of C++. By then if you feel up for it, go for "C++ Coding Standards" (Sutter & Alexandrescu) and then "Modern C++" (Alexandrescu) (these two, along with the actual C++ Standard documentation, are the only books I ever refer to).

Also, get …

L3gacy commented: good tips +1
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

What you need to do is dereference the y pointer. There are a couple of ways to do it:

1) the * (star) is a dereference operator when applied to a pointer variable:

int x = *y; //gets the value that y points to.

2) the is a dereference operator that also allows you to get the value at "i" integers from the address stored in y (i.e. this indexes into an array):

int x = y[0];  //gets the value that y points to.
x = y[2];      //gets the value 2 integers after y[0].
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

**PLEASE USE CODE TAGS** it's horrible to read this post.

I did manage to spot this: char *p = strtok((char*)s.c_str(), " "); You cannot use strtok() with an std::string! What is returned by c_str() is a read-only char array. The c_str function returns a constant pointer, but it should return a constant pointer to constant, meaning you should not modify the characters it points to (the reason why it doesn't is for compatibility with C).

Basically, the C++ std::string is not anything like a C-string (const char*) and should not be used as such. The c_str() function is just provided for convenience of being able to _read_ the string as a C-string, it is not for writing. It might work, but that is just accidental.

C++ has it's own set of functions for extracting different things from a std::string, and those are the functions you should use. Most of them are collected in an object of class "std::stringstream" (in #include <sstream>) which can be used in a similar fashion as cin or cout (or any other IO stream), but from or to a string instead of the console or file. Here is how to extract that first token from the C++ string:

std::stringstream ss(s);   //create a stringstream from the string s that you have.
std::string p;             //create a string to hold the first token.
std::getline(ss, p, ' ');  //extract string up to the first space character from ss.
WaltP commented: So I added CODE tags for him. Did it help? +15
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Wow, "delete this;"... I can't begin to tell you how unsafe this is.

>>is such a method recommended?
Here is my scale in C++:
- Desirable (includes things like RAII, exception-safety, binary compatibility, generic implementations, concept checking, const-correctness, etc.)
- Recommended (includes things like programming-by-contract, independence, abstraction, encapsulation, non-copyable, smart pointers, etc.)
- Acceptable (includes things like the visitor pattern, dynamic casts, etc.)
- Lesser evil (includes things like singleton patterns, fly-weight idiom, union-types, raw-pointers, etc.)
- Last resort (includes very few things that are horrible, like const-casts and C-style casts, for example)
- Forbidden, horrible, disgusting, evil code (includes almost nothing, but it includes "delete this;")

What if your object is allocated statically (not with new)?
What if your object is allocated as part of an array?
What if there exists another pointer to your object?
...
These are all perfectly normal uses of a class in C++. And they would all lead to a disaster if you decide to do a "delete this;" statement. The const_cast and setting this to null is completely useless. You have contrived an example in which this works, but that's just a very special case. In most cases, the this pointer won't relate to anything meaningful in the caller's code (in a method, the this pointer should always be treated as a read-only local variable, there is no guarantee that treating it any differently will be valid).

If you …

VernonDozier commented: "Forbidden, horrible, disgusting, evil code" +13
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Ok, let me clarify what I think you mean. You would like to have a Log class that does something like this:

class Log {
  private:
    std::ofstream outFile;
    //..
  public:
    Log(const std::string& filename) : outFile(filename) { /*..*/ }; 
    
    void recordEntry(const std::string& S1) {
      //..
      outFile << S1;
    };

    void recordEntry(const std::string& S1, const std::string& S2) {
     //..idem
    };
    
    //... so one for any number of strings. 
};

Well, you might want to learn a few things about templates in C++, before going to deep into this Log class.

C++ does not really support variadic functions (i.e. functions with variable number of arguments) (actually, it does, but it's not type-safe and very ugly, and I don't really know how to use that obscure feature). So, basically, you would have to write a function overload for each different number of parameters (just restrict it to 10 or something like that).

I want to point out two things. First, if you use templates, you will not be restricted to only strings. You can make overloads that take any sequence of parameters of any type:

class Log {
 //.. as before ..
   //say for 3 arguments:
   template <typename A1, typename A2, typename A3>
   void recordEntry(A1 a1, A2 a2, A3 a3) {
     outFile << a1 << a2 << a3; //this will allow you to record anything that can be outputted to a ostream.
   };
};

Second, I want to point out that the upcoming C++ standard (now called C++0x) will include …

daviddoria commented: Very thorough answer! +5
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Whatever it is that is causing this behaviour is not standard. When I tried your program, line 6 would output garbage regardless of line 12 and 14 being commented or not, as expected. It might simply be that your compiler puts "cow" from line 12 temporarily on the stack frame of main, than frees that piece of the stack frame, and when you call farm1, the cow variable in farm1 just ends up occupying the same place on the stack and thus has a value of 10. In other words, its just incidental. The expected behaviour is for cow in farm1 to have a garbage value when outputted, it's just that in this case that garbage value ends up being 10 because of what was executed just before the function call. Basically, the 10 is a garbage value.

Try this for example:

#include <iostream>
using namespace std;

int cows = 10; //global variable

void farm1()
{
    int cows;
    cout<<"in farm1, cows="<<cows<<endl;
    cows++;
}

int main()
{
    cout<<"in main, cows="<<cows<<endl;
    farm1();
    farm1();
    farm1();
    farm1();
    farm1();
    cout<<"back in main, cows="<<cows<<endl;
}

See how the garbage value is continuously reused because the local "cow" always takes the same place on the stack frame.

jonsca commented: Seems plausible. +7
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You have no breaking condition in your getline function. The while loop that uses is.get(), when applied to the standard input stream, will never end. Normally, this loop would end when you hit the end-of-file, but cin never reaches that point, it has no end. When there is nothing remaining on the input stream, the get function will just wait forever. Why not implement a true replacement to the getline function:

std::istream& getline(std::istream& is, Str& s, char delim = '\n'){
	s.clear();
	char c;
	if(is){
		while((is.get(c)) && (c != delim))
			s.push_back(c);
	}
	return is;
}
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

This is a classic problem, you have a dangling new-line character on the input stream. You need to call ignore() right after you input the character to clear that dangling new-line. So, at line 31:

cin >> ans;
cin.ignore();
Khoanyneosr commented: Thanks so much! I'm new to coding and I really appreciate your help. +0
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The formula used for rand48, minstd_rand and the built-in rand() function is the linear congruence formula:

x(n+1) = (a * x(n) + c) % m;

Where a, c, and m are fixed parameters and x(0) is the seed value. Any of the random number generators you have proposed are more complex than this and is very unlikely to be any faster. I find it very bizarre that computing the above formula would take up so much of your computing time (unless all you program does is generate random numbers). The reason why rand() might be faster is because rand() is built-in, and thus, it could have been implemented as inlined assembly code (although fairly unlikely). This is actually the implementation of rand():

int __cdecl rand (void) {
  return (((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
};
void __cdecl srand(int seed) {
  holdrand = seed;
};

rand() is not perfect, but simplicity and speed are not part of its problems. As for Boost.Random, using the basic linear congruence methods should be just as fast unless your compiler really sucks. I tested the following program on my computer (with Linux and GCC 4.6.0):

#include <cstdlib>
#include <ctime>
#include <boost/random/linear_congruential.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

int main() {

  std::srand((unsigned int)time(0));
  boost::rand48 rng((unsigned int)time(0));
  boost::minstd_rand rng2((unsigned int)time(0));

  boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time();
  for(unsigned int i=0;i<1000000;++i)
    rand();
  boost::posix_time::time_duration dt = boost::posix_time::microsec_clock::local_time() - start;
  std::cout << "rand() generated 1000000 numbers in " << dt.total_microseconds() << std::endl;

  start = boost::posix_time::microsec_clock::local_time();
  for(unsigned int …
Zjarek commented: It saved my day +2
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>How do you pass an unknown object into a function and save it?
It all depends on how "unknown" the object is. There is a big difference between "it could be one of a few different types" and "it could be of absolutely any type that exists or will ever be created". In either case, the solutions you posted are probably the worst, and that is because C++ is a strongly typed language and there is a good reason why that is... breaking type-safety with a cast to void* is always the very last resort (and very rarely needed in pure C++, if ever).

If it is of only a small number of possible types, you can use a union type. Say you could store an int, a double or a char, Then you could do this:

class MyClass {
  private:
    union value_type {
      char c;
      int i;
      float f;
    };
    value_type data; //data will hold any of the union's member types.
  public:
    //just let type-safe overloading work its magic:
    void set(char value) { data.c = value; };
    void set(int value) { data.i = value; };
    void set(float value) { data.f = value; };
    void get(char& result) { result = data.c; };
    void get(int& result) { result = data.i; };
    void get(float& result) { result = data.f; };
};

If you have more complex types, you can still use the same mechanism: use a union to store any of the types you are expecting and use parameter-type …

mrnutty commented: exactly +7
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

As Agni suggested, you can group all those delays/timers into one singleton object. The same mechanism applies when it comes to calling from the same thread as foo was created or calling from any thread. I will just make an example for calling from the timer thread (you would just have to replace the callback by setting of a flag to signal the call on the original thread).

#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
#include <map>

class publisher {
  private:
    typedef std::multimap< boost::posix_time::ptime, boost::function<void()> > CallBackMap;
    typedef CallBackMap::iterator CallBackIter;
    CallBackMap callbacks;
    boost::mutex callbacks_mutex;
    boost::thread publishing_thread;
    void execute() {
      while(true) {
        {
          boost::unique_lock<boost::mutex> lock(callbacks_mutex);
          CallBackIter it_end = callbacks.upper_bound(boost::posix_time::millisec_clock::local_time() + boost::posix_time::milliseconds(20));
          for(CallBackIter it = callbacks.begin(); it != it_end; ++it)
            it->second(); //call the callbacks that are scheduled.
          callbacks.erase(callbacks.begin(), it_end); //erase callbacks that were called.
        }; //release lock.
        boost::this_thread::sleep(boost::posix_time::milliseconds(20)); //sleep 20ms 
      };
    };

    //private constructor. Will start the execution thread.
    publisher() : publishing_thread(boost::bind(&publisher::execute,this)) { }; 
    publisher(const publisher&); 
    publisher& operator=(const publisher&); //non-copyable.
  public:
    void subscribe(boost::function<void()> f, boost::posix_time::time_duration dt) {
      boost::unique_lock<boost::mutex> lock(callbacks_mutex);
      callbacks.insert(std::make_pair(boost::posix_time::microsec_clock::local_time() + dt, f));
    };

    static publisher& getPublisher(); //singleton.
};

publisher& publisher::getPublisher() {
  static publisher p; //will be created on first use.
  return p;
};

class foo {
  public:
    void my_delayed_method() {
      std::cout << "Hello World!" << std::endl;
    };

    foo() {
      publisher::getPublisher().subscribe(boost::bind(&foo::call_method_with_delay,this), boost::posix_time::seconds(60)); //subscribe for a callback in 60 seconds.
    };
};
Agni commented: Very helpful code +4
arjunaw commented: Kudos to you for taking the time to write sample code showing what you mean. Much appreciated. +0
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Also, there is a lambda function used I would like to remove without adding another function.

That's easy. Your Lambda is only calling the isspace function, just replace it with the isspace function. As so:

sum = std::count_if(left.begin(),left.end(),std::isspace);

>>I'm comparing a std::string::difference_type to a std::string::size_type

That's ok, it only issues a little warning. If you want to avoid the warning, cast the diff_type variable to the size_type type. Or, you can use end() - begin() to get the size as a diff_type instead of a size_type.

>>Any ideas for an algorithm change?

I think the algorithm is OK. You might simplify the code using more <algorithm> and <functional> utilities. Also, you should probably use the "assign" function instead of clear and insert on lines 41 to 46. The whole #define business for the reversion of the string is very awkward and unecessary. Either choose one, or implement the operator to take an inserter (front_ or back_insert_iterator) as second argument instead (with a default overload for a string). Finally, notice that line 49 is not going to delete the trailing space characters in the left string (you could just use left.end() for the end of the range to erase).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

All your huge switch-statement does is:

get a seat selection X
-> if X is out-of-range or not available, then ask for another seat selection.
-> otherwise, reserve seat X

Your C++ code for doing this should be no more than 5-6 lines of code long, if you just follow the above pseudo-code (and use an array to store the seats as reserved or not). I wish I could just write the code for you, but this is something for you to do on your own. Just a little example on how to use an array:

#include <iostream>

int main() {
  char my_array[9]; //declares a fixed-size array of 9 characters.
  my_array[0] = 'a'; //access the first element of my_array with index 0 (indices start from 0).
  my_array[2] = 'c'; //e.g. this sets the 3rd element to the character 'c'.
  //you can loop through an array with a for-loop:
  for(int i=0;i<9;++i)
    my_array[i] = ' '; //this sets all elements of my_array to the space character.
  //you can also access the elements for printing them:
  for(int i=0;i<9;++i)
    std::cout << my_array[i] << "|"; //prints all elements separated by '|'.
  std::cout << std::endl;

  return 0;
};

In the above, you have all the information you need to turn you thousand-something lines of code to less than a few dozen lines of code.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

When you pass the object by value (not pointer or reference), a copy of the object is made and used as the parameter. Because the parameter is of type Base, the new object (the copy of the passed object) is of type Base, regardless of the type of the object that is given as parameter to the function call, as long as there is a way to make an object of type Base from the object that is passed to the function call. By default, the compiler generates a copy-constructor for Base that takes an object of type Base by reference (to which an object of type Der can be implicitly cast to).

In summary, here are the cases:

#include<iostream>

class Base {
  public:
    virtual void fun()
    {
      std::cout << "base" << std::endl;
    };
};

class Der : public Base {
  public:
    void fun() {
      std::cout << "Der" << std::endl;
    };
};

void func_by_value(Base b) {
  b.fun(); 
};

void func_by_ref(Base& b) {
  b.fun();
};

void func_by_ptr(Base* b) {
  b->fun();
};

int main() {
  Base b;
  Der d;
  b.fun();          //output: "base"
  d.fun();          //output: "Der"

  func_by_value(b); //output: "base"
  func_by_value(d); //output: "base"
  func_by_ref(d);   //output: "Der"
  func_by_ptr(&d);  //output: "Der"

  return 0;
};

If you want the equivalent of passing-by-value, i.e. you don't want to allow modification of the original object, you can pass by const reference.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

-Wall stands for -W (warning) and all (for "all"). It just is a command-line argument to the compiler to tell it to report all warnings about your code. If you don't enable this, the compiler will only report errors that prevent it from compiling the code. If you enable all the warnings, it will report many things that are indications of possible mistakes that you could have made (e.g. using single = (assignment operator) in an if-statement, casting a double variable to an int (that will result in a loss of information), and many other little things that can come from either typos or poor coding practices (like C-style casts)). This is a general rule for good programming practices: "enable all warnings and treat them as if they were errors" (i.e. fix your code such that the compiler doesn't complain about anything).

When you are using an IDE (eclipse, VC++, Code.Blocks), you typically enable all the warnings via the "build options" for your project (in the menus, find "build option" or something similar, and then you should be able to find a large list of "compiler options" from which there are several options that relate to warnings, they pretty much should all be enabled (checked)).

Personally, I don't understand why all warnings are not enabled by default, because they should (i.e. it should be that compiler options are used to disable warnings that are all enabled by default).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

What happens is that the default constructor for the object is invoked (which in this case happens to be 0). Try doing it with an object that doesnt have a default constructor and you will see what I mean.

@L7Sqr: I'm sorry, but I have to correct your statement. I think it is an important point to clarify. Primitive types such as int or int* do not have a default constructor (or, equivalently, their "imaginary" default constructor does not initialize the memory in any way). However, there is the concept of default-initialization in C++ which is invoked with the following syntax:

int* b = new int(); //the int to which b points to is default-initialized.
struct Foo {
  int value;
  Foo() : value() { }; //the "value" member is default-initialized. 
};

When this default-initialization is used one of the following happens (C++ Standard 8.5/5):

To default-initialize an object of type T means:

— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

— if T is an array type, each element is default-initialized;

— otherwise, the object is zero-initialized.

The standard also clearly states at 8.5/9 that, if no initializer is specified for an object of POD-type (which includes primitive types), then the object and any of its sub-objects have "indeterminate initial value".

Basically this means that the following this true (and can be tested to be true):


       
L7Sqr commented: Thanks for the clarification. +1
jonsca commented: Good information +7
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You could simply use the Boost.Function and Boost.Bind utilities, as follows:

class MyClass
{
public:
  double Update1();
  double Update2();
  double Update3();
  boost::function< double() > Update;
private:
  float Data1;
 ...
  float DataN;
};

Then, define them as:

class MyClass
{
 int UpdateMethod;
};

void MyClass::SetUpdateMethod(int method)
{
 if(method == 1) 
   this->Update = boost::bind(&MyClass::Update1,this);
 if(method == 2) 
   this->Update = boost::bind(&MyClass::Update2,this);
 if(method == 3) 
   this->Update = boost::bind(&MyClass::Update3,this);
}

Now, MyClass.Update can be called as any other member function.

A slightly more customized version of this would be by using a pointer to the member function and just calling it on this within the Update() function.

daviddoria commented: Very cool, thanks for the suggestion! +5
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Serialization 101:

class oserializer; //forward declaration
class iserializer;

//create a base abstract class for all serializable objects:
class serializable {
  public:
    virtual oserializer& serialize(oserializer&) const = 0;
    virtual iserializer& deserialize(iserializer&) = 0;
};

//create a serializer class (for saving, o for output):
class oserializer {
  private:
    std::ostream out_file; //hold a file to write to.
  public:
    oserializer(const std::string& filename) : out_file(filename) { };
    
    //Create a bunch of overloads of operator << for each primitive types:
    oserializer& operator <<(const int& value) {
      //save to the file, any way you like (e.g. binary or XML), say binary:
      out_file.write((char*)&value,sizeof(int));
      return *this;
    };
    // ... and so on for all primitive types (unsigned int, char, float, double, etc.)
    
    //Then, write a few overloads to handle some common STL containers (technically you have them all):
    template <class T>
    oserializer& operator <<(const std::vector<T>& vec) {
      *this << vec.size(); //keep a record of the size, this will be useful for loading.
      for(std::vector<T>::const_iterator it = vec.begin(); it != vec.end(); ++it)
        *this << *it; //save all the elements using one of the primitive overloads.
      return *this;
    };
    //so on for the other STL containers.

    //now, write an operator for a serializable object:
    oserializer& operator <<(const serializable& obj) {
      return obj.serialize(*this); //just call serialize.
    };
    //provide one for a pointer too: (or better: a smart pointer)
    oserializer& operator <<(const serializable* obj) {
      return obj->serialize(*this);
    };
};

//now you can create classes like this for example:
class Foo : public serializable {
  int a;
  float b;
  char c;
  public:
    virtual oserializer& …
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

If you look at my last answer to this thread, you will see that you are in case number 5, i.e. you have an object hierarchy with cross-references between objects (via pointers). As with many programming problems there are three ways to solve it: the good, the bad and the ugly.

The Good: Use a library that is already established and highly regarded, if it serves your need. In this case, Boost.Serialization. I know, the code in it is not exactly "simple" for a beginner. But if you can bare it, use it.

The Bad: Make your own home-brewed serializer. This is bad because it is reinventing the wheel and it is tedious to make it robust (or you have to leave it in a fragile state, which is worse). Anyhow, for this, you would have to have a class that handles all the I/O with the file. That class should keep a record of all objects (non-primitive) (by pointer) which are saved so that it doesn't repeat or go into an infinite cycle. I could go on explaining it, but I think you could be looking for the Ugly way instead.

The Ugly: Write a quick and dirty, single serving solution. In this case, you can assume that all drivers can saved as part of the save function of the team object. So, the driver class probably shouldn't save the team pointer that is has. So, in a save/load function in CTeam, you just …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Line 40, the single equal sign should be doubled == for comparison. Compiling with all warning on would have caught that typo (use -Wall as a compiler flag).

Transcendent commented: thanks man +0
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

@NathanOliver: The <algorithm> version of sort cannot be used for the list container because it requires a random-access iterator (and list is a linked-list so it only provides a Forward and Backward Iterator concept). The way the OP did is correct.

@atticusr:
The sorting algorithm relies on the comparison (by default) of two elements using the < (less-than) comparison. So, the underlying type has to have that operator defined. In other words, if you have "list<MyType> l; MyType a, b;", you have to be able to write "a < b". To be able to do that for a custom type, you need to overload the operator <. As so:

struct cProg3
{
  char lname[21];
  float avg;
  int gSize;
  cProg3();
  void Read_m(fstream &Infile);
  void Read_g(fstream &Infile);
  //Overload operator < here:
  bool operator < (const cProg3& other) const {
    return (avg < other.avg); //compare by average.
  };
};

That should work.

NathanOliver commented: thanks for straightening me out with that +2
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The compiler "mike_2000_17" gives this error:
"Error at line 34: function "GetOddElements" reaches end-of-scope without returning a value"

The reason why your version that uses references is not working is because references are not copy-assignable, which is a requirement of all STL containers.

As for the bigger question. This is not a very robust way to have a sub-vector that is linked to another vector. You should look into the concept of "array views" (used in several libraries such as Boost.Graph, Boost.Multi-Array or -Index, and others too). Basically, you should wrap a reference to the vector object and define some index transformation to change the "view" that this object takes on the underlying container (this is for example a nice way to implement the transpose of a matrix without any copying).

daviddoria commented: Thanks as always Mike! +5
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Well, GLUT is a limited library. It is not really meant for complex applications. Why don't you use wxWidget or Qt to create the window then and render your openGL scene inside the wxWidget window, as in this tutorial. And even better for Qt.

Nick Evan commented: Excellent advice as (almost) always ;) +16
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The strtok function:
"A null pointer is returned if there are no tokens left to retrieve."

You should handle that case. Possibly in your isValid() function (like a test for NULL before all the strcmp calls).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>The nice way, however is to create a class 'Student' and overload the >> operator, but for now the above should do fine.

And the _easy_ way is to use std::getline() from the <string> header. As so:

string fullName;
  getline(cin,fullname);

that will capture everything until the return key is hit.

For your second question, just use std::vector instead of an array, as so:

vector<string> studentName(numberOfStudents);

You can access the elements just like you do for a static array.

thelamb commented: Not really sure how that slipped my mind... thanks +3
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>why not explain where and how they are normally used in bigger programs(programs that use API, GUI or more than a console window)?

HANDLE is a standard Windows pointer type. If you go to msdn.microsoft.com and make a search for "HANDLE" under win32 API, you will find 495,000 hits (just about every function in the win32 API). Is that enough examples for you?

Qt is a cross-platform tool for building GUIs, in that framework, almost every significant piece of the GUI is stored and used via a pointer to it. This is mainly because of polymorphism in OOP. Although they often use smart-pointers too (which you may or may not consider to be a pointer).

The vast majority of libraries that you can use via DLLs or shared libraries have C-style interfaces that pass pointers to-and-fro their API functions (like Win32 does). A simple example is FreeImage that is a library used to load, manipulate and save any image file format. When you want to access the image's data (like pixels), you call a function, get a pointer back, and dereference the pointer to access the data. A huge number of libraries work in a very similar way.

..... blablabla .... the number of examples of real-life uses of pointers is uncountable. They are ubiquitous. They are only (almost) avoidable in open-architecture projects (basically a library with which you interact directly with the source code of the library and not with an API or …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

For an offline version, you can probably google around and find some version of it (might not be the exactly appropriate one, but it usually should be). For example, here you can download all the STL documentation in a zip or tarball (as offline html files) (it doesn't include iostreams and string functions and classes, only STL containers and algorithms).

EDIT: I also found this one which seems to be fairly complete, recent enough and from a trusted source (IBM).