glumesc

December 22, 2009

Why are c++ forums so combative?

Filed under: Comment, Development — Tags: , — steve @ 10:13 am

Over the course of my career I have, on occasion, had to fall back to trawling various software-related forums for help and advice. Although you occasionally get the odd troll, I have generally found that forums that cover topics such as HTML, PHP, Perl, Java and C# tend to be helpful and friendly. This is in stark contrast to forums that specialize in C++.

Almost without exception, posts by people who are obviously lacking in C++ experience are answered by at least one person who feels it necessary to take them to task, in no uncertain terms, for their lack of knowledge or, something I always find amazing, their coding style. While I recognize that coding style has a big affect in the maintainability of the code, I fail to see why someone who is obviously trying to learn the language should be attacked in quite so vociferous manner.

I can understand constructive criticism, which, when presented in a friendly manner, can be very helpful is shaping people’s coding styles, however I fail to see the benefit of making people feel like idiots just because they haven’t had 20 years experience of hardcore C++ development.

I should point out that is not a gripe from personal experience – I have yet to post a question to a C++ forum exactly because they appear so intimidating – however it always strikes me as odd that the C++ development community seems so unwilling to welcome new blood into their midst.

December 18, 2009

In which our hero learns about forward declaration

Filed under: Development — Tags: , , — steve @ 5:12 pm

And so, the latest step up the steep learning curve that accompanies C++ is completed. Let’s start with some code.

The following is a heavily simplified version of a CLI wrapper that I am writing to expose some unmanaged C++ libraries to C#:

Elephant.h: Elephant.cc:

#pragma once

#include "UnmanagedElephant.hh"
#include "Water.h"

namespace Jungle
{
    public ref class Elephant
    {
        public:        
            Elephant();

            ~Elephant();

            Water^ GetWater();
    };
}}}}


#include "Elephant.h"

using namespace Jungle;

Elephant::Elephant()
{
    /* code */
}

~Elephant::Elephant()
{
    /* code */
}

Water^ Elephant::GetWater()
{
    return gcnew Water();
}

Water.h: Water.cc:

#pragma once

#include "UnmanagedWater.hh"
#include "Fish.h"

namespace Jungle
{
    public ref class Water
    {
        public:        
            Water();

            ~Water();

            Fish^ GetFish();
    };
}}}}


#include "Water.h"

using namespace Jungle;

Water::Water()
{
    /* code */
}

~Water::Water()
{
    /* code */
}

Fish^ Water::GetFish()
{
    return gcnew Fish();
}

Fish.h: Fish.cc:

#pragma once

#include "UnmanagedFish.hh"
#include "Water.h"

namespace Jungle
{
    public ref class Fish
    {
        public:        
            Fish();

            ~Fish();

            Water^ GetWater();
    };
}}}}


#include "Fish.h"

using namespace Jungle;

Fish::Fish()
{
    /* code */
}

~Fish::Fish()
{
    /* code */
}

Water^ Fish::GetWater()
{
    return gcnew Water();
}

The first build error this produced was the following:

error C2512: no appropriate default constructor available

This was produced at the Water^ GetWater(); line of Elephant.h.

After much poking around the web, I stumbled across the page mentioned in my previous post. This pointed me to the need to add #ifndef/#define/#endif flags around the code to prevent header files being included multiple times while compiling a source file (I had previously assumed the “#pragma once” statement was sufficient).

After adding these flags to the header files so they looked like this…

Elephant.h:

#pragma once

#ifndef INC_ELEPHANT_HPP
#define INC_ELEPHANT_HPP

#include "UnmanagedElephant.hh"
#include "Water.h"

namespace Jungle
{
    public ref class Elephant
    {
        public:        
            Elephant();

            ~Elephant();

            Water^ GetWater();
    };
}}}}

#endif

…the error disappeared to be replaced by the following:

error C2143: syntax error : missing ';' before '^'

Again, this was produced at the Water^ GetWater(); line of Elephant.h.

So, back to the web. Unfortunately this is an exceptionally vague error that basically means the compiler got confused for some reason and the line in question is the last line it encountered before it all went pear shaped. This took a *long* time to figure out.

More by luck than judgement, I finally staggered across the following post: http://www.codeguru.com/forum/showthread.php?t=383253 . This highlighted the fact that circular dependencies among includes is a very bad thing. The solution is to use “forward declaration”, which essentially means adding a reference to the class to the header file and adding the include statement for that class to the source file.

In my case, the problem was the fact that Elephant included Water which included Fish which included Water. The inclusion of Water’s headers twice caused the compiler to get its knickers in a twist.

The final solution looks like this:

Fish.h: Fish.cc:

#pragma once

#include "UnmanagedFish.hh"

namespace Jungle
{
    ref class Water;

    public ref class Fish
    {
        public:        
            Fish();

            ~Fish();

            Water^ GetWater();
    };
}}}}


#include "Fish.h"
#include "Water.h"

using namespace Jungle;

Fish::Fish()
{
    /* code */
}

~Fish::Fish()
{
    /* code */
}

Water^ Fish::GetWater()
{
    return gcnew Water();
}

Here endeth the lesson.

C++ Basics: How include statements work

Filed under: Development — Tags: , — steve @ 10:24 am

Nice discussion/explanation of how #include statements work in C++, including tricks to avoid common problems:

http://bytes.com/topic/c/answers/132010-how-do-header-files-work

December 14, 2009

In which Boost rears it’s ugly head again…

Filed under: Development — Tags: , , , — steve @ 10:28 pm

And so on to my next problem, which again turned out to be due to my good friend Boost.

Background:

  • Visual Studio 2008
  • 32bit Project containing a managed CLR wrapper on some unmanaged C++ libraries
  • The unmanaged libraries reference a version of Boost compiled using Visual Studio 2005.
  • Messages at compilation time: Linking to lib file: boost_thread-vc90-mt-gd-1_39.lib
  • Error message:  fatal error LNK1104: cannot open file 'boost_thread-vc90-mt-gd-1_39.lib'

The more sharp-sighted amongst you will have quickly noticed the reference to “vc90″ in the lib file name, implying the libraries were compiled with Visual Studio 2008.  This is odd because the libraries are most definitely called boost*vc80*.lib.  Where was Visual Studio picking up this reference to vc90?  There was no reference to vc90 in the project properties, which implies that Visual Studio was dragging this out of thin air.

After a fair amount of investigation, my suspicions finally fell up the Boost includes.  The cause had to be something in the boost include files that wass forcing the assumption that the libraries had been compiled with VS2008.  A quick search revealed the following culprit: include/boost/config/auto_link.hpp

The auto_link.hpp code includes a section that searches for the _MSC_VER environment variable (which is set by Visual Studio). If BOOST_LIB_TOOLSET is not predefined, _MSC_VER is used to infer the relevant compiler version (vc80, vc90 etc).  The BOOST_LIB_TOOLSET property is then used to construct the file names for the libs to be linked.  Thus, since I was using VS2008, BOOST_LIB_TOOLSET defaulted to vc90.

The solution was to add the following to the Preprocessor Definitions: BOOST_LIB_TOOLSET=vc80

Once set, _MSC_VER was ignored and everything compiled as expected.

64bit application “is not a valid Win32 application”(!)

Filed under: Development — Tags: , , — steve @ 10:27 pm

This took me ages to find the solution: a 64bit application running on XP64 throws the following exception:

System.BadImageFormatException: is not a valid Win32 application

My immediate reaction was “well thanks for pointing out the obvious!”.  Unfortunately sarcasm didn’t resolve the fact that the application would not run.

The obvious things were checked:

  • The solution and all its projects were being compiled as x64
  • dumpbin reported all the DLLs (including third parties) as x64

I did manage to narrow the source of the problem down to one DLL: a managed CLR wrapper on some unmanaged C++ libraries.

After much hunting around I finally found the following post that indicated this might due to boost, upon which the C++ code depended.  This eventually led me to this post, which proved to be the solution. 

In summary: ensure boost libraries are linked dynamically rather than statically by specifying BOOST_ALL_DYN_LINK in the Preprocessor directives of the C++ project.

Theme: Silver is the New Black. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.