Go Premium for a chance to win a PS4. Enter to Win

x

C++

57K

Solutions

24K

Contributors

C++ is an intermediate-level general-purpose programming language, not to be confused with C or C#. It was developed as a set of extensions to the C programming language to improve type-safety and add support for automatic resource management, object-orientation, generic programming, and exception handling, among other features.

Share tech news, updates, or what's on your mind.

Sign up to Post

Bloom Filter
Looking for a way to avoid searching through large data sets for data that doesn't exist? A Bloom Filter might be what you need. This data structure is a probabilistic filter that allows you to avoid unnecessary searches when you know the data definitely won't be found. Read on to find out more...
5
Hire Technology Freelancers with Gigs
LVL 11
Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the basics of OOAD by referring the real time objects.
0
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation, easy programming and fast execution.
6
 

Expert Comment

by:Chad B
Comment Utility
Good article but needs proof reading and cleaning up.  For example, there is more than one place that says the opposite of what is intended (e.g. "Like Java and C++, go is not object-oriented...").
0
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so many programmers use void as the return type. People, I'm sorry to tell you but that's just plain wrong!

The C/C++ standards are very (VERY) clear about the prototype for the main function. It can be one of the following two (and only the following two) formats:
 
int main(void) { /*...*/ }

Open in new window

and
 
int main(int argc, char *argv[]) { /*...*/ }

Open in new window


Any other prototype is ill-defined and will result in undefined behaviour. Don't be fooled into thinking that it must be okay to have void as the return type because, if it wasn't the compiler would chuck an error. Actually, the C / C++ standard does not require the compiler to do this. All the standard states regarding this matter is:

"If the main function executes a return that specifies no value, the termination status returned to the host environment is undefined."
Now, the chances are that you'll never see the effect of your mistake directly. By the time the brown stuff hits the fan, your program has likely ended. No, it won't be you who gets caught out, it'll be the user of your program who suffers at your hands.

You see, all processes return an exit code, that just happens to be …
4
 
LVL 58

Expert Comment

by:tigermatt
Comment Utility
A nice article and clearly a bug bear issue in software which exhibits these traits. Thanks. If the programmer did not see fit to define a sound interface with their program through attention to detail over return values, I would assume quality issues abound with the rest of the software, and would not hesitate to assume compiling it could result in a program which deletes all my data. [Through programmer incompetence or compiler-writer foolhardiness. They are invoking undefined behaviour, after all. :-)]

Some questions / remarks:

Common case behaviour

In reality, despite the standards, how do compilers behave in the common case? If I wanted to see the effects of this for myself, in code I compile, how would I do so?

I suspect the common case is that a (sane) compiler assumes what the programmer intended and synthesises a return of 0? This is certainly the behaviour I experience with gcc on a generic GNU/Linux x86 box. For example, the below:
#include <iostream>

using namespace std;

int main(void)
{
        int x = 3+4 * 5;
        cout << x << endl;
}

Open in new window

compiles down to:
000000000040082d <main>:
  40082d:       55                      push   %rbp
  40082e:       48 89 e5                mov    %rsp,%rbp
  400831:       48 83 ec 10             sub    $0x10,%rsp
  400835:       c7 45 fc 17 00 00 00    movl   $0x17,-0x4(%rbp)
  40083c:       8b 45 fc                mov    -0x4(%rbp),%eax
  40083f:       89 c6                   mov    %eax,%esi
  400841:       bf 80 10 60 00          mov    $0x601080,%edi
  400846:       e8 75 fe ff ff          callq  4006c0 <_ZNSolsEi@plt>
  40084b:       be 30 07 40 00          mov    $0x400730,%esi
  400850:       48 89 c7                mov    %rax,%rdi
  400853:       e8 c8 fe ff ff          callq  400720 <_ZNSolsEPFRSoS_E@plt>
  400858:       b8 00 00 00 00          mov    $0x0,%eax
  40085d:       c9                      leaveq 
  40085e:       c3                      retq   

Open in new window

In particular, the compiler in this case seems to have synthesised an explicit mov of constant value zero to EAX before the return, presumably by assumption that this is what I intended when flowing off the end without an explicit return statement.

I appreciate the GNU Compiler Collection is a behemoth, so what do I need to do to actually observe random values returned from the accumulator register? Use some other simplistic / esoteric compiler, perhaps a very simple one which receives little attention and generates code for some relatively obscure architecture? Something else?

To be clear, I am not advocating a wilful disregard for the standard; quite the contrary. However, I often find constructive examples can be useful in motivating a change in programmer behaviour, rather than arguments from standards (which often seem to fall on deaf ears or false arguments of "it doesn't affect me" or "my compiler is better than that").

Compiler warnings

Should the compiler warn me if there exists a path in the flow graph of a function returning a non-void type which fails to explicitly call return before the end of the function? Should it do this for the main method? Details of specific compilers are well outside the scope of the article, but I note in gcc's man page, the return-type warning explicitly excludes warning about the main method. Why should this be the case?

For C++, a function without return type always produces a diagnostic message, even when -Wno-return-type is specified.  The only exceptions are main and functions defined in system headers.

Infinite loops

What are the correct semantics here? Do I need to / should I be forced to include a return value? What about if I do this outside main(), where switching on return-type warnings throws an error about a missing return statement which would otherwise never be reached? (Assuming C++)
int main(void)
{
        while (true)
        {
                // do something
        }
}

Open in new window


Other functions

The following compiles but I presume it would be unwise to assume that anything will be well-defined after the call to foo() in main() which excludes a return statement?
int foo(int x, int y)
{
        /* something happens here */
}

int main(void)
{
        int bar = foo(3, 4);
}

Open in new window


These questions / remarks are not intended as a criticism of the article, so please don't misconstrue them as such! There are a fair few nuances in such a seemingly simple topic which are worth further exploration.

So, thoughts?
0
 
LVL 40

Author Comment

by:evilrix
Comment Utility
>> In reality, despite the standards, how do compilers behave in the common case

It's really hard to say because it depends on both the compiler and the optimization level to which the code has been compiled. Generally, compilers use the accumulator to return values so whatever was last placed in that register is what will be used. There are no guarantees to this; however, and the only sane (and correct) answer I can give you is that the behaviour is undefined.

>> compiles down to:
Remember, it depends what optimization level you built with. The outcome in terms of assembly code can be very different depending on whether you built optimised for speed or performance and to what level you optimise to.

>> seems to have synthesised an explicit mov of constant value zero to EAX before the return
If this is C++ then, yes, it will.

"Interestingly, whilst the main function MUST be defined to return an int, in C++ you don't have to actually return anything from main. The main function is treated as a special case; whereas, if you omit a return value the C++ runtime will automatically return zero for you."

I can't say for sure, but I have a feeling the C++ standards council made this change to account for the fact people were declaring main to return void. If you were to do the same here you would probably still see zero returned due to the fact the accumulator is being zero'd out; howver, in truth the behaviour is undefined - always was and alway will be (at least until the standards council say otherwise).

>> so what do I need to do to actually observe random values returned from the accumulator register?
Change there return type to void and compile as C not C++ code.

Or, you could try this...

#include <ctime>
#include <cstdlib>

int foo()
{
   return rand();
}

int bar()
{
   // look ma' no return value!
}

int main()
{
   srand((unsigned)time(0));
   
   foo();
   
   return bar(); // should return the return value of foo() (random)
}

Open in new window



>> Should the compiler warn me if there exists a path in the flow graph of a function returning a non-void type which fails to explicitly call return before the end of the function?
Interestingly enough this is not considered an error to not return a value from a function, it is considered to be undefined behaviour. This means the compiler does not have to generate an error but it will probably generate a warning (as long as warning levels are high enough). I suspect the reason is because it is possible to embed assembly into C/C++ code and so the function stack may be modified by the programmer outside the semantics of the C/C++ compiler's remit.

>> I note in gcc's man page, the return-type warning explicitly excludes warning about the main method. Why should this be the case?
Almost certainly because you can embed assembly into manipulate the function's stack-frame, which might be used to generate perfectly valid code but which the C/C++ compiler cannot validate and so will generate a warning.

>> Infinite loops - What are the correct semantics here? Do I need to / should I be forced to include a return value?
The compiler doesn't care - for the sake of sane program exit, maybe :)

>> where switching on return-type warnings throws an error about a missing return statement which would otherwise never be reached?
Well, that's a completely different problem - one of inaccessable control paths. Again, the standard does not mandate any warning be given for this and so that is compiler specific.

Other functions - The following compiles but I presume it would be unwise to assume that anything will be well-defined after the call to foo() in main() which excludes a return statement?
It's probably more correct to say the result is platform specific rather than undefined because it's really down to how the compiler works and it may be that this is actually intended (see my previous observation about embeding assembly). This code is not erroneous, it's just going to behave in a way that is arbitrary unless the programmer really knows what's going on at the assembly level and is controling it in some way.

>> These questions / remarks are not intended as a criticism of the article, so please don't misconstrue them as such!
All interesting points that makes me feel a separate article might be worth writing to cover in more detail the nuances of why there are somethings that would seem completely erroneous that the compiler will let you do and why somethings are undefined and some are unspecified (and what the difference is).

Matt, I hope my comments, above, help.
0
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode? They will have you believe that Unicode requires you to use a WCHAR (wide) character type and that Unicode cannot be represented by a CHAR (narrow) character type. In fact, both of these statements are completely and utterly false. Microsoft has misled you in the most egregious way.

Before we go any further, I need to clarify some terminology that is often confused. This is especially true of Windows programmers who, quite often, mistakeningly believe that using a wide character type means they are using Unicode:

Character Set: This is a complete set of characters recognized by the computer hardware and software.

Character Encoding: This is a way of encoding a character set, generally to fit within the boundaries of a particular data type. ASCII, ANSI and UTFx are all examples of character encodings.

Character Type: This is a fundamental data type used to represent a character.

These three things are intrinsically related. The character type chosen to represent a character set will have a direct impact on the character encoding used. In C++, the normal fundamental character types are either wchar_t (wide) or char (narrow). The size of the narrow and wide types are platform dependent, although C++11 has introduced fixed sized
7
 
LVL 32

Expert Comment

by:DrDamnit
Comment Utility
"When Microsoft gets involved."

You had me at the title.

Excellent work, sir.
0
 
LVL 29

Expert Comment

by:pepr
Comment Utility
+1 ... not because it helped myself [learned via more painful way], but because the articles like that should be spread to enhance the future. It the past, it was a lot of discussion about UTF-8 being impractical "because you cannot seek to the position". Actually, languages like Python 3 show, that beginners need not to care about how it is implemented inside. A unicode character is represented by a number (as one logical unit). If the programming language gives you tool for accessing the parts of the string easily you do not want to care about how many details must be solved. You simply enjoy when it works (and you feel safe when you know it is not an ad-hoc solution with some dark corners).
0


You've created a class and during its construction an exception is thrown. Question: should you catch it? Answer, it depends!

Let's explore.

When deciding whether to catch the exception ask yourself a very simple question. If you do catch it can you still leave the class in a usable state? If the answer is yes, then by all means catch it, deal with it and allow construction to continue. If the answer is no then do not catch it! Why? Simple! if you catch and swallow it, how is the code that was attempting to construct your class to know that the class is unusable (or, at least only partially constructed)?

You could add a method that returns a boolean value to identify the class failed to construct but that will only lead to more complications and will just make life hard for everyone; you and the user of our class. You'll be giving them the abitilty to work with a partionally constructed object and the chances are that isn't a sane thing to do.

For example, what happens if the user tries to call a function on your partial construction, and almost certainly, not-so-sane class? What if failure to construct has left the class with an unassigned member pointer and that calling any or all of the member functions requires the pointer to be dereference it? Bad things will happen. It will end in tears. Kaboom!

Your solution? You'll now have to add even more code in each public function to check for this kind of issue to make sure the program doesn't crash. …
0
You're implementing a beautiful class. It's just wonderful - the most perfect code you've ever written, except... for some reason it keeps crashing and you don't know why. You've debugged the code and discovered it happens when your class goes out of scope and needs to throw an exception from the destructor. Tested in isolation, this works fine but integrated into the main code base it causes a crash. You know there are exception handlers that should deal with this and yet it still crashes. This doesn't make sense. Why is the crashing?

As part of the development of this class it was necessary to write some complex "clean-up" code in the class destructor, but there is the possibility that something could fail during the clean up. For example, maybe our use case for the class is an object that represents a database connection and the destructor is finalising any outstanding transactional data commits before the object goes out of scope.

Your class can't just leave these commits unfinalised as that could leave the database in an inconsistent state, but the process can fail. What do you do? You have to handle these commits but they can go wrong and so you have no choice but to throw an exception of course, right? Wrong! This really is about the most dangerous thing you could possibly do! Also, if your class is written correctly it should be completely unnecessary.

Here's a question for you. Let's say the destructor of your class is being executed because the stack is …
1
First of all, this article is NOT going to explain C++ references and pointers. If you are not clear on what these are then this is quite probably the wrong article for you and you really should probably go read here, here or here.

In C++ all arguments are passed to functions by value. In other words, a copy of the value is taken and that is what the function has to work with. If you want to modify the original value you must either pass a pointer or reference to the original value you wish to modify. Of course, even the pointer or reference are still passed by value. Pointers and references are just another C++ type and when they are passed around you do so by value.

Now, what about the case where we don't want to modify the value? There's no need to pass by reference or pointer, right? Wrong! Now, in the case of fundemental types it probably doesn't make a huge deal of difference since these are unlikely to be any more complicated that a pointer or reference type; howver, in the case of fully blown class objects, such as string, vector, map, set or any other (including your own class objects) it can make a huge difference. You see, passing by value can be very expensive both in terms of memory usage and performance (time / space complexity)

Classes have copy constructors, which are defined to facilitate the correct copying semantics for a class. Now in C++ there are two types of copy, shallow and deep
2

Personal disclaimer

Before going any further I want to make it clear that the contents of this article express my personal opinion. You are perfectly free to disagree and I respect your right to do so. That said, you are highly unlikely to convince me that learning C is a valuable path to learning C++ so whilst I do appreciate any comments you might have on my article, posting long-winded arguments to the contrary is probably pointless. What I'd suggest you do is go write your own article instead and I'll be more than happy to link to it as a counter-argument.

So, with that said, here goes...
 

C is Not C++!!!


A superset of nothing useful

I often hear those who really should know better giving the advice that before you learn to code in C++ you should first learn to code in C. At face value this would seem like reasonable advice; after all C++ is a superset of C and so by learning C you'll be learning some of C++. Unfortunately, this advice overlooks some fundamental but very important differences between C and C++ that may very well damage the learning curve of the student.

The main problem is that to say C++ is a superset of C greatly overstates the relationship. It is a superset but only insofar as the core syntax of the languages is very similar. As programming models go the two languages could hardly be further apart. It's like arguing the case for learning to ride a push-bike before learning to drive a truck because both have …
20
 
LVL 14

Expert Comment

by:Alexander Eßer [Alex140181]
Comment Utility
Awesome! Thank you ;-)
0
 

Expert Comment

by:EDWIN DELGADO
Comment Utility
What a good, clear to the point, concise and clear short description about the difference of C and C++, and its scope of applications ........ thanks for this!  I strongly agree based in my short experience in embedded systems and mains stream programming.
0
Abbreviations:
COM - Component Object Model.
ATL - Active Template Library.
TLB- Type Library

Why Using ATL?
It Provides ready made stuffs needed for creating and using COM component.

Why Use COM?
COM is language independent. Any client(C++/scripting) can use COM component.

Brief Description about COM:
  • Interface is the base class and Component is the derive class.
  • Component class implements the methods inside interface to make it usable.
  • All COM components derived from IUnknown interface(provides AddRef(),Release() and QueryInterface()).
  • We needn’t have to implement these interfaces as wizard will do the implementation for us inside our component class.
  • All these stuffs would be taken care by ATL COM Wizard.
  • IUnknown interface does Life time management of the component.
  • Any method we want to implement needs to be added to the interface and we have to implement those methods inside component class.
  • Once our component is ready, we have to register the component dll in windows registry by using regsvr32. It’s inbuild in windows OS.
  • To Use any COM component, we need 2 files. DLL and TLB(Type Library)
  • DLL holds actual COMPONENT and .tlb having details information about the component. Like function parameter/Argument type/return type and which interface this component implements.
Creation of COM component:

Steps for creating Server:
  1. Open Visual Studio 2010
  2. File->New->Project->create ATL project, name it as DemoServer.
Settings11.jpg       
Click OK.
  • Settings10.jpg
 
  • Settings9.jpg
 

 
2
 
LVL 6

Expert Comment

by:rr_miles
Comment Utility
Well done. Thank you.
0
[Webinar] Cloud and Mobile-First Strategy
LVL 11
[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

Inspired by The Zen of Python and with a wink and a smile, and tongue firmly in cheek, I hope this will bring a smile to you C++ programmers.

Are you a C++ programmer who works with Python programmers? Are you fed up with them banging on about their "Python Philosophy"? Do you feel like beating them over the head with your compiler every time they witter on about using 4 space intending? Does the fact they continuously try to convince you enforced white space syntax is a good thing just make you want to hurl chunks? If so, what you need is "The Zen Of C++"!

The Zen of C++:

Beauty is but skin deep.
Explicit is implicit.
Why be simple when we can use meta-templates?
Complex is better when more complicated.
Nested is fun but tail end recursion rocks.
C++ is better than Python.
Readability counts for nothing.
Special cases aren't special enough if they don't break the rules.
Forget practicality; you're an artist so let your creativity flow.
Errors can be ignored; that's what default exception handlers are for.
Supress all compiler warnings -- you know best!
In the face of ambiguity, resort to templates.
There should be one-- and preferably only one --obvious way to do it; but don't let that stop you inventing others.
Although that way may not be obvious, which clearly means a better way exists (probably using lots of templates).
Now is the best time to introduce unnecessary complex constructs otherwise you may never get around to it.
1
Smart pointers - Are they really that smart?

You might have heard something called smart pointers on your lectures, or that many game companies use them. The reason why just you, should use them might not be clear. Even if you would want to use them you may not know how you do that. The reason why you may not know that, is because the use of templates. Without templates, these smart pointers would actually be more accurate called "dumb pointers." We will cover "dumb pointers" later in our goal to achieve smart pointers.

What are smart pointers, and what are they good for?

Smart pointers is basicly your typical object. However, this object is built to be a container of sorts, a container that stores another object of chosen type. This container can then later call upon it's content and all it's member methods and attributes. That gives us the very specific advantage of calling upon the content object deconstructor, meaning removing it from memory automatically.

The reason why this are good, is pretty straight forward. To decrease the number of bugs you probably will run into, if you would not to be using it.

When you create a program, you do not want memory leakage or memory that takes room without reason. Ideally, you want to load your object into memory, and delete it as soon as it is not going to be used again.

The most common error, that will happen in your program, will be that you allocate memory, and never release it. When you create a …
0
 
LVL 3

Author Comment

by:fjocke
Comment Utility
Hi Sara, this is actually a typo from my end. Naturally it should deallocate the memory, and then set the pointer to null. Thanks for spotting it for me :)
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
I covered the full implementation of reference counted smart pointers here:
http://www.experts-exchange.com/articles/1959/C-Smart-pointers.html
0
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects.

A brief on problem:
Lets take example problem for simplicity:
- I have a GSM network with a cell in it.
- Cell's coverage area is divided into a pixel grid with dimensions 2000x2000.
- at each pixel the signal strength is measured.
Requirement is to find out the % of pixels in a cell that have below par signal strength.

Solution 1 using the good old C:
In C, memory is dealt in raw. You want memory, allocate the number of bytes you want. No guarantees are give regarding the contents of that memory (using malloc()). At best you can initialize the whole block of memory you allocated with "zeros" (calloc() or memset()), but not to a value specific to your application (not unless you REALLY go deep into how your specific compiler creates the memory map for your data).
// Solution 1
#include <stdio.h>
#include <stdlib.h>
#define GRID_WIDTH 200
#define GRID_HEIGHT 200
#define MIN_SIGNAL_STRENGTH 3

typedef struct pixelStruct {
    int _x;
    int _y;
    int _signal_strength;
} t_pixel;

void print_pixel( const char* msg, const t_pixel* ptr ) {
    cout << msg << endl << "\tptr = 0x" << hex << ptr << ", x = " << ptr->_x << ", y = " << ptr->_y << ", signal_strength = " << ptr->_signal_strength" << endl;
}

int main() {
    t_pixel* pixelArray[GRID_WIDTH][GRID_HEIGHT];

    srand ( 

Open in new window

0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Nice article, but I do have so reservations about placement new in general.

Firstly, you could probably achieve the same (or quite similar) performance gains by allocating objects rather than pointers to objects in the vector.

My main concern with placement new is that its semantics are very different from normal operator new and a lot of caveats need to be considered. For example, if the constructor of the object being supplanted throws the memory it is being supplanted into will leak because, unlike normal construction semantics, there is nothing to release that memory. This may or may not lead to a problem depending upon how your memory pool is managed.

My point is that placement new requires some very special care when being used and shaving a few microseconds for heap allocations when a different design might achieve the same result is probably not a good enough reason for making use of this feature of C++.

Just my 2 pence worth.
0

This article is a discussion on smart pointers, what they are and why they are important to C++ programmers. Following the primary discussion I present a simple implementation of a reference counted smart pointer and show a simple example of using it. Although this article does not go into detail about how to develop a reference counted smart pointer the example code at the end is very well commented and that should be enough to aid understanding.


This article is targeted at an intermediate level C++ programmer; however, anyone who develops using C++ (even as a student) would benefit from reading this article and taking to heart the principles it discusses even if you don't follow all of the technical concepts introduced. Not all the terms I use are necessarily explained in this article (I've kept it focused on the core subject); however, anytime a new term is introduced it will be linked to a reference where you can find out more.


Please note, all the code shared in this article is my own; however, during the development of my smart pointer I used the Boost shared_ptr as a basis for the interface to ensure I had captured all the necessary ingredients to provide a fully working smart pointer. If you have access to Boost then, please, do use the range of high quality, peer reviewed smart pointers provided in preference to the one I discuss here. My example, although fully working (and bug free I hope), is meant for educational purposes rather than use in production code and doesn't, for example, implement support for thread safety or intrusive reference counting.


What is a smart pointer? That is a very good question... I'm glad you asked. First, though, allow me to introduce you to my cleaner Raii (pronounced Rye). Her job is to clean up after me. I'm pretty messy, I often get things out and forget to put them back but good old Raii follows me around and when I'm done with something she puts it away for me. Raii can be your cleaner too if you ask her. Isn't she nice? Would you like me to introduce you to her? Yeah? Okay, say hello to Raii or Resource Acquisition is Initialisation to give her her full and rather grand title.


Okay I admit it,  Raii isn't a real person; rather, she's a C++ idiom also, sometimes, referred to as a design pattern. Basically, anytime you allocate a resource you immediately initialise a Raii object with this resource and for the lifetime of the Raii object your resource is accessible but as soon as the Raii object is destroyed it automatically cleans up your resource too. So what does this have to do with smart pointers? Well a smart pointer is just a specialised Raii pattern. It specialises in managing the lifetime of heap allocated memory and will dispose of it when it is destroyed.


So, how does that work? Good question, I am so glad you asked! Let's take a look. Firstly, the following is a very simple example of allocating heap memory in a function.


void foo()
                                        {
                                           int * pi = new int;
                                           // Do some work
                                        }


Not much going on there, except did you spot the defect? That's right, the memory isn't deleted when the function ends. See how easy it is to forget? What about this example?


void foo()
                                        {
                                           int * pi = new int;
                                           // Do some stuff
                                           delete pi;
                                        }


Great, memory is deleted no defects there right? Wrong! What if "Do some stuff" throws an exception? When an exception is thrown unless there is a catch handler to handle it the function it is thrown from will immediately exit, the function that called it will also immediately exit if that doesn't have a catch handler and so on until an appropriate catch handler is found or the application terminates. This is called Stack Unwinding. Great, makes sense right? You'd hope so since this is ingrained within the C++ standard!


So, can you see the problem (and I'm not talking about the exception causing the program to terminate, let's assume for the sake of this discussion somewhere further down the stack the exception is caught and handled)? That's right, who deletes the memory allocated in the foo() function? Answer -- no one does! Once again we have a memory leak. So how do we handle this? The obvious solution is to catch the exception, deleted the memory and tr-throw it, right? Ok, let's try that.


void foo()
                                        {
                                           int * pi = new int;
                                           try
                                           {
                                           // Do some stuff
                                           }
                                           catch(...)
                                           {
                                        	   delete pi;
                                        	   throw;
                                           }
                                           delete pi;
                                        }


Great, leak plugged... except... well it's a bit messy isn't it? We now need to have the same pointer deleted twice in one block of code. The general rule of thumb is don't duplicate code as it just makes for extra maintenance. Is there a better way? Well, yes... again we turn to the C++ standard and we find those nice people who provide the language (The C++ Standards Committee) have thoughtfully provided a smart pointer called std::auto_ptr (it lives in the <memory> header file). A smart pointer will automatically delete the memory it is managing once it goes out of scope. How? Well, remember how destructors of classes are automatically called when the class is being destroyed? Well, all that happens is we pass the smart pointer a real pointer that is pointing to heap allocated memory (normally via its constructor, hence the idiom Raii) to manage and when it goes out of scope (and, thus, is destroyed) its destructor deletes the memory for us. Neat eh? So, does this help? Let's see.


#include <memory>
                                        void foo()
                                        {
                                        	// Note, the constructor of auto_ptr is explicit so you MUST use explicit
                                        	// construction (pi = new int; will cause a compilation error)
                                           
                                           std::auto_ptr<int> pi(new int); 
                                           
                                           // Do some stuff
                                        }


Fantastic, problem solved! No need for catch handlers, no duplicate code and the auto_ptr will automatically delete the memory allocated to it when it goes out of scope, when the foo() function ends. Great, time for a cup of tea and feet up, right? Um, no. You see auto_ptr has a couple of unfortunate problems that can catch out the unwary programmer. Let's take a look.


Problem one: The auto_ptr type can only be used with scalar heap allocations


That's right, when you allocate memory using new and delete you have to use different syntax for scalars vs. arrays. Let's take a look.


	int * pi = new int; // Allocate a scalar
                                        	delete pi; // De-allocate a scalar
                                        
                                        	int * pi = new int[10]; // Allocate an array
                                        	delete [] pi; // De-allocate an array


You can't mix up new and delete with new [] and delete []. You must pair them off correctly, otherwise the result is undefined (assume this is bad!). Now auto_ptr is designed specifically to delete scalars.


NB. The C++ Standard provides a better solution for allocating dynamic arrays, it's called a vector.



Problem two: The auto_ptr type has the concept of ownership, also know as move semantics. Let's take a look.


#include <memory>
                                        void foo()
                                        {
                                           std::auto_ptr<int> pi(new int); 
                                           
                                           bar(pi); // this function accepts a std::auto_ptr<int> by value
                                           
                                           // Do some stuff using pi
                                        }


The moment you call the bar() function and pass it pi, the ownership of the pointer is passed from the original pi to the one that is within the stack frame of the bar() function. When this function returns ownership is not transferred back to the original pi auto_ptr. What does this mean in simple words? When you assign pi to another auto_ptr ownership is transfered to the new auto_ptr and the original auto_ptr no longer contains a pointer to the memory it was managing, instead it now points to NULL and any attempt to use it after that will result in undefined behaviour (assume this is bad!). This is like giving your mate the money from your wallet and then going to the shops -- you have nothing to pay with so it'll end in tears!


In fact, this is one of the more obvious examples, where it's clear to see what's happening. Imagine the auto_ptr was a member of another class and this was passed by value to another function, unless you're written your own copy-constructor and/or assignment operator (note, you should always implement them in pairs) to perform a safe deep-copy you'll hit the same problem. The auto_ptr member will move ownership to the new copy and the current auto_ptr member will no longer point to valid memory. It's fair to say that auto_ptr can be very dangerous indeed!


Ok, so what do we do now? It's clearly too dangerous to use heap allocation in C++ so we'll all just become .Net managed code programmers right? Eeeek, no! Arrrrr! Quick... it's time for me to introduce our saviour, the reference counted smart pointer. Now, straight off the bat let me say that there is no default implementation of a reference counted smart pointer in C++ (yet) but the one that comes with Boost is ubiquitously use and looks to become part of the next C++ Standard, C++0X.


So what is a reference counted smart pointer? Well, unlike auto_ptr a reference counted smart pointer doesn't transfer ownership. You can copy it as many times as you like and each smart pointer will contain the same pointer to the same object.


How does it work? Well, as well as containing a pointer to the memory it's managing a reference counted smart pointer also contains a pointer to a counter and when you copy it the counter is incremented. The copy will point to the same object being managed and the same counter and when this goes out of scope it will decrement the counter but NOT delete the memory being managed unless the counter indicates this is the last reference. Let me say that again. Every time a copy of the smart pointer is made the counter is incremented and every time a copy goes out of scope the counter it is decremented.


When the counter reaches 0 that means the current copy going out of scope is the last one to reference the pointer being managed so it can safely delete the memory pointed to by the pointer without fear that another smart pointer will try to use it. It's like a bus driver who counts all the people getting on the bus and all the people getting off and when the bus is empty he can park up and have a nice cup of tea.


Still not convinced for the case for using reference counted smart pointers over raw pointers? Think you're too good for them? You never forget to release memory, right? Wow, you're a tough audience! Okay, what's wrong with this then?


class foo
                                        {
                                        public:
                                        	foo() : pi1_(new int), pi2_(new int) {}
                                        	~foo() { delete pi1_; delete pi2_; }
                                        private:
                                           int * pi1_;
                                           int * pi2_;
                                        }


Nothing wrong there, right? Wrong! What if the allocation of pi2_ fails? That's ok foo's destructor will delete pi1_ right? Um no! You see destructors aren't called if the construction fails due to exception percolation. Ok, shall we try again? Sure, how about this?


class foo
                                        {
                                        public:
                                        	foo()
                                        	{
                                        		try
                                        		{
                                        			pi1_ = new int;
                                        			pi2_ = new int;
                                        		}
                                        		catch(...)
                                        		{
                                        			delete pi1_;
                                        			delete pi2_;
                                        			throw;
                                        		}
                                        	}
                                        	~foo() { delete pi1_; delete pi2_; }
                                        	
                                        private:
                                           int * pi1_;
                                           int * pi2_;
                                        }


Great, no more leaks right? Right! Except... um, now if pi1_ throws you'll try and delete pi2_ as well and since that currently contains an uninitialised value we'll try and delete an invalid pointer and corrupt the heap (this is really bad!). Ok, so we can get around this by initialising both pointers to be NULL in the constructor initialisation list (it's safe to delete NULL) but look what a mess we now have. Imagine if the class was more complex than just these 2 pointers!?


class foo
                                        {
                                        public:
                                        	foo() : pi1_(0), pi2_(0)
                                        	{
                                        		try
                                        		{
                                        			pi1_ = new int;
                                        			pi2_ = new int;
                                        		}
                                        		catch(...)
                                        		{
                                        			delete pi1_;
                                        			delete pi2_;
                                        			throw;
                                        		}
                                        	}
                                        	~foo() { delete pi1_; delete pi2_; }
                                        	
                                        private:
                                           int * pi1_;
                                           int * pi2_;
                                        }


Ok, this solves the problem but what a mess? Also, what happens if the re-throw was accidentally omitted from the catch block? Well, construction wouldn't fail (since we blocked its failure) and the destructor will still be called. Meanwhile you'd probably (but not necessarily, sometimes we want to block failure) then try to use a class that wasn't correctly constructed and make a right old jolly mess!


Did someone scream function try block at me? Okay, I'll humour you, let's try again.


class foo
                                        {
                                        public:
                                        	foo()
                                        	try: pi1_(new int), pi2_(new int)
                                        	{
                                        	}
                                        	catch(...)
                                        	{
                                        		delete pi1_;
                                        		delete pi2_;
                                        	}
                                        	
                                        	~foo() { delete pi1_; delete pi2_; }
                                        private:
                                           int * pi1_;
                                           int * pi2_;
                                        }


Fantastic, a solution that doesn't use smart pointers! Two things though. First, how many C++ programmers even know about function try blocks? Actually not very many! The syntax can be quite confusion for someone who isn't well versed in them. Second, the catch block in this example never re-throws (just like I discussed above) so this constructor can't fail then right? Oh if only the C++ standard were that simple and consistent. The answer is (come on you knew I was going to say this right?) yes it most certainly can!


You see with a constructor try block if an exception is thrown during construction it will always (yes, that's right, always) percolate it even if you don't re throw it yourself. Actually, that's a good thing normally, but not always. You might have a valid case to not re-throw, the exception might not necessarily mean construction failure. The only way to solve this is to nest yet another try block. Wow, what a tangled web we weave.


Ok, let's look at the very simple way to solve this using smart pointers.


class foo
                                        {
                                        public:
                                        	foo() : pi1_(new int), pi2_(new int) {}
                                        
                                        private:
                                        	// These are reference counted (soon to be discussed below)
                                           smart_ptr<int> pi1_;
                                           smart_ptr<int> pi2_;
                                        }


Wow, now that is simple. Each smart pointer is allocated a memory to manage and when the class goes out of scope each will delete that memory. If the construction fails any memory allocated will be correctly deleted and if the smart pointer was never constructed because the object being constructed before it throws an exception it'll never try and delete memory that it was never constructed to start with. Simple eh?


What I'd like to do now is to introduce you to my very own hand crafted reference counted smart pointer. Now it's important to note that although the following code is a fully functional, it is really for educational purposes only. It has not been tested in a production environment (I wrote it just for this article) and if you do decide to heed the advice and use smart pointers please do refer to the Boost implementation as your first port of call.


So, without further ado, here she is in all her majestic glory (*cough*)...


20
 

Expert Comment

by:Rulsan Burakov
Comment Utility
typedef delete_scalar_policy<ptrT> delete_policy_;
here probably it should be destruct_policy.
0
 
LVL 40

Author Comment

by:evilrix
Comment Utility
Good spot. Fixed and added a credit to the article. Thanks.
0

Introduction

This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more complex, you may need to use additional techniques. This article focuses on the Watch Pane, examining blocks of memory, and viewing memory at different levels of the Stack Frame.


TABLE OF CONTENTS
1.  Watch Pane
1.1.  Adding entries
1.2.  Viewing Pointers as Arrays
1.3.  Watching Expressions
1.4.  Watching Error Status
2.  Viewing Memory Regions
2.1 Opening a Memory Pane
2.2 Debugging with Integer Array Representation
3.  Viewing Memory in the Stack Frame

1. Watch Pane

A Watch Pane, like the Autos and Locals Panes, also shows variable names, values, and types.  It is especially useful for watching global objects which never show up in a Locals Pane. Unlike the Autos and Locals Panes, the Watch Pane is not filled in automatically; you need to insert the names yourself. In addition to variable (or object) names, you can also enter expressions to evaluate.

As you step through your program, if the item you are watching changes its value, then the value will appear in red.

1.1.  Adding entries

There are several ways to enter names or expressions into the Name list.
Figure 1 shows how to use the Add Watch
8
 
LVL 61

Administrative Comment

by:mbizup
Comment Utility
Awarded Editors' Choice

mbizup
EE Page Editor
0
Templates For Beginners

Or

How To Encourage The Compiler To Work For You


Introduction

This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more advanced topics. Although the material covered here is, indeed, about templates please don't think that this tutorial covers all you need to know. The subject of Templates is such a deep topic that complete books have been written about it; however, that's not to say this tutorial isn't complete, but that it will cover only the basic knowledge that you'll need...


What Are Templates And What Are They Used For?

Two good questions and perhaps the only ones that matter at the minute. To begin, let's start with what they're used for. Assume I asked you to write a function to add two integers together, you'd most likely come up with something like this:

int addTogether(int a, int b){
	return a+b;
}

Open in new window


If I then asked you to overload the function to add two doubles together, you would most likely overload the function as follows:

double addTogether(double a, double b){
	return a+b;
}

Open in new window


Now I then asked you to do the same for unsigned integers, strings and a few classes I wrote (which, no doubt, would be equally as useless as this addTogether function), you would probably be thinking two things. Firstly, you would be questioning my ability to reason correctly if I …
4
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Great article for beginners... received my "yes" vote above.
0
 
LVL 60

Expert Comment

by:Kevin Cross
Comment Utility
I wholeheartedly agree, thank you very much!
Voted yes above, also.
0
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automatically each time the field/variable is used.  Alas, standard C++ does not directly support such a concept, but this article discusses some options you can use to implement properties in your C++ objects.

Properties are a first-class language element of C#, Visual Basic, Delphi, Python and other languages.  Over the years, proposals have been submitted to C++ standards committee to add the feature to our favorite programming language, but it's never quite made it into an official standard.


Why Properties?

What's the point?  Why use properties?  

The main idea is based on something that programmers have been struggling with probably ever since Lady Lovelace wrote the first computer algorithm -- data encapsulation.  You want to manage and limit direct access to data elements so that only those parts of the program that need it can get to it.  But the usefulness of properties goes well beyond that.  Here are some things you can do with properties and some examples:
 
Data encapsulation, data hiding.  Prevent direct manipulation of data elements.  Avoid programming errors related to changing a data value incorrectly or at the wrong time.

Example:
6
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Hi Baldrick2.

I'm not really sure I understand the relevance of the link you've posted. For the sake of informing myself and others could you just clarify?

Thanks.
0

Introduction

This article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article located in Part 1, and as you get more familiar with the debugger, you may be interested in some additional miscellaneous tips in Part 3.



As assignments become more complicated (e.g., more loop iterations, more recursion, more function nesting), the tips shown below may further help improve your productivity.

For this article, all projects are built using a “General Empty” project. The first project reads in a very large list of scrabble words, and determines the largest set of anagrams in the list.

TABLE   OF   CONTENTS

1.  Conditional Breakpoints
2.  Hit Count Breakpoints
3.  Touch and Go Breakpoints (a.k.a. Tracepoints)
4.  Exception Breakpoints
4.1.  Change How the Debugger Handles an Exception
4.2.   Adding a User Defined Exception
4.3.   Breaking on a User Defined Exception
5.  Run To Cursor (Create a Temporary Breakpoint)
6.  List of Breakpoints

1.  Conditional Breakpoints

The program is reading in thousands of words. Suppose you suspect there is a problem after the program reads in a word beginning with “lap”. Rather than hit F5
7
 
LVL 32

Author Comment

by:phoffric
Comment Utility
Thanks torimar for your comment. Glad you found it a pleasure to read.
0
 
LVL 61

Administrative Comment

by:mbizup
Comment Utility
Awarded Editors' Choice

mbizup
EE Page Editor
0

C++ Properties


One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property. These are like data members except they can have preconditions imposed on them prior to getting or setting their value. In C++ the general way to implement property like behaviour is to have a getter and/or setter member function. For the most part this suffices but there is an issue with this approach: you lose the syntax and semantics of a data member and, instead, have to deal with the syntax and semantics of a member function.

What do we mean by this? Let's take a very simple example class called "account" that contains an int called "balance_".

class account
{
public:
   int balance_;
};

Open in new window


As it currently stands "balance_" is a public data member. Although this gives us access to "balance_" it's uncontrolled - no preconditions can be imposed. This is bad OOP design. It means "account" has no control over the value of "balance_" and so cannot guarantee the value is sane. In other words we could set balance_ to any rogue value that may or may not be appropriate for what it represents. Let's make a change to ensure this is no longer the case.

class account
{
private:
   int balance_;
};

Open in new window

8
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
Good article!  Got my YES vote!
0
 
LVL 40

Author Comment

by:evilrix
Comment Utility
Thank you Dan.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE
LVL 5
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Introduction

This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on the Watch Pane, examining blocks of memory, and viewing memory at different levels of the Stack Frame.


Motivation To Begin Learning

NOTE: If you just want to get started quickly using the debugger, then SKIP this Motivational paragraph.

This article is intended to help students become quickly comfortable with the VS 2008 Express Debugger.  Students beginning in their study of C/C++ may shun the use of the very powerful symbolic debugger because of their belief that the learning curve is too prohibitive; after all, they have been successfully writing and debugging programs for the first couple of months using print statements.  But as the programs become a little longer and bugs creep in – and now, for some reason, it is harder to track down the problems.  The purpose of this article is to demonstrate that in a few minutes, a student can learn enough to significantly improve their productivity in completing assignments.

Some of the website tutorials on this topic are too…
9
 
LVL 32

Author Comment

by:phoffric
Comment Utility
Rick,
I was in the process of moving sections 2-xxx to separate follow-on articles (to keep the first article extremely simple - as we had discussed) when it was accepted. I can start that process today.
    Paul
0
 
LVL 61

Administrative Comment

by:mbizup
Comment Utility
Awarded Editors' Choice

mbizup
EE Page Editor
0
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why they are such an integral part of the Standard Template Library as a whole.  If you are unfamiliar with STL containers, I would suggest reading evilrix's article Which STL Container? before you continue.

A Brief Overview of the STL

The STL is primarily composed of three different types of entities: containers, algorithms, and iterators.  Containers are written as template classes, and that means they are instantiated using a special argument referred to as a template argument, which is always a data-type (e.g. int, string, float, etc.).  When you create an STL container, the template argument you pass in specifies the type of the data you are holding within the container (syntax: 'list<int> myList' for creating a list container named mylist for holding integers).  The second entity type, algorithms, are functions capable of using and manipulating the data held within STL containers.  Algorithms typically take in a range of …
1
 

Expert Comment

by:2x2makes11
Comment Utility
It is not a good idea to write code like
std::cout<<std::endl<<std::endl<<"text"

Open in new window

And it's not good to use std::endl instead of '\n' just to use some different thing.
The '\n' and std::endl differs so that std::endl not only prints '\n' char, it flushs a stream buffer else.
If you aware that program can suddenly crash, you should write std::endl to ensure that buffer will be flushed, and text will be written to stdout just after writing statement (you write "text\n"). But if you just srart to write a text, why do you flush a buffer? Not just flush it, you flush it twice!.

If you want to separate leading '\n' from string, you can just write
std::cout<<"\n\n" "text"

Open in new window

I think it's more readable, and it won't do useless work.
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
2x2makes11,

Whilst your point is valid it's not really the point of the article and is, thus, really unimportant in the context of what this article is actually discussing.
0

 
Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and when to use it.

This article is a guided tour of the STL containers. It is not intended to teach you how to use each of these containers; rather, it will help you decide when and where to use each of them. It will also show you a few tips, tricks and snippets of information that are not normally documented elsewhere but may come in handy.
 
The target audience for this article is intermediate and above. I don't necessarily discuss every new concept I introduce but every time a new and important concept is introduced I will be sure to provide a link to a reference where you can read more if you need to.

This article discusses the following STL containers:
vector
deque
list
set
map
multiset
multimap
bitset

vector


The vector is a sequence container that represents an abstraction of a dynamic one dimensional array. It manages an internal buffer which can automatically grow to accommodate the contents. The allocation strategy used to allocate the internal buffer is not defined by the C++ Standard and is dependent upon the allocator
9
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
Thanks, evilrix.
Maybe you can make something similar about the iterators? from your practical point of view
0
 
LVL 12

Expert Comment

by:trinitrotoluene
Comment Utility
great article!

something on Boost next for novices....i know u r a Boost proponent ;-)
0

1. What is C++ STL?

STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector.

2. C++ classic fixed size arrays

Everyone who has ever programmed in C++, has came across the classic fixed-size array. Here is an example.
//declare array (indexes are from 0 to 999 (1000 elements), be careful)
int arr[1000];

int num;

cout << "How many numbers will you write?" << endl;
cin >> num;

//read NUM integers and write them into array
for(int i=0; i<num; ++i) {
	cin >> arr[i];
}

Open in new window

In this example we have read num elements from the user and stored them into array. If we wanted to read more than 1000 values, we would overflow the array, resulting in undefined behaviour. The place for 1000 integers is defined when program is compiled and cannot be changed at runtime. This can be overcame by dynamic memory allocation. (See below)

3. C++ dynamic memory allocation arrays

Take a look at the following code snippet:
int num;

cout << "How many numbers will you write?" << endl;
cin >> num;

int *arr=new int[num];
for (int i=0; i<num; ++i) {
	cin >> arr[i];
}

delete arr[];

Open in new window

Firstly, we ask an user to tell us, how many numbers he wants to input and then we read them. This is a lot better, we can allocate the required amount of memory at runtime instead of declaring fixed array of a very big amount of integers, hoping user won't overflow the array with his choice how many numbers he wants to input. Don't forget to delete the allocated array at the end of your code and free the used memory.

The more modern way of doing this is a vector, which can change its size during the program execution. We will take a look at it in the next chapter.

4. C++ STL Vector

1
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
Good article!  You explained it very well.  I look forward to additions to this series.
0
Written by John Humphreys

C++ Threading and the POSIX Library

This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.  
[step=""]Before we start, I want to say that every time I show source code, it is tested.  And for every modification, I will provide the complete code in so you can just copy paste and try it out yourself.  This means some parts of the code examples are repeated... but it's that way just for your convenience!  I didn’t put my output in here, but you shouldn't need it -- you have the compiler command, so take the 20 seconds to paste it in and do it yourself.  Doing is learning after all :)[/step]
Just to get it out of the way, POSIX stands for Portable Operating System Interface for UNIX.  POSIX is a set of standards (basically common APIs) that operating systems must support in order to be assigned the UNIX branding.   Most versions of Linux support the POSIX libraries as well.

The POSIX threading library is very commonly used for threading on supporting operating systems.  This article will tell you what a thread is, how it exists in the operating system, how to create threads and manage threads, how to synchronize threads, and how to enforce mutual exclusion with the POSIX libraries (if you don’t know what mutual exclusion and critical sections are, you will learn that too!).

So, what is a thread?

In…
6
 
LVL 12

Author Comment

by:w00te
Comment Utility
Thanks :)
It's always nice to hear some nice feedback!
0
 
LVL 9

Expert Comment

by:Subrat (C++ windows/Linux)
Comment Utility
After a long time sending my +1.
0
The beauty of XML is that it is simple "eyeball-readable" text.  Bring it up in any text editor or web browser, and you have an easy direct way to debug it and find problems.  Sure, it can be handy to use a complex object like MSXML or a third-party XML parsing utility when processing and interpreting the XML, but to generate XML output, you can use simple string-manipulation functions.

Some time ago, I needed to output some database records using a certain XML schema.  I spent time figuring out how to make SQL Server do it automatically, and I found some other tools... but as soon as I needed to do anything at all unusual, I found myself spending more time working around the tool quirks than doing the actual programming.  These monolithic programs and objects made it too complicated.  After all, for the most part, XML is very simple:

    < tagName > data goes here </tagName >
...or...
    < tagName attrName = value > data goes here </tagName >

In the data goes here spot, there can be additional <tagName>...</tagName> sequences.  What could be simpler?

It's just an issue of inserting textual data in between tags.  To my eyes, it looks like a perfect spot to use C++'s printf-style formatting specifications and its Variable Argument List capability.  For instance:

   prinft("<LastName>%s</LastName>\r\n", rc.sNamelast );
   prinft("<Age>%d</Age>\r\n", rc.nAge );
   prinft("<Hair color=%s style=%s
2
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
Nice. Helpfull. Thanks.

Regards,
Pavel
0

C++

57K

Solutions

24K

Contributors

C++ is an intermediate-level general-purpose programming language, not to be confused with C or C#. It was developed as a set of extensions to the C programming language to improve type-safety and add support for automatic resource management, object-orientation, generic programming, and exception handling, among other features.