Thread: strings in header files

  1. #1
    Registered User
    Join Date
    May 2009
    Posts
    242

    strings in header files

    I can't seem to figure out the correct syntax for using non-primitive data-types in header files. Can someone please help?

    Here's an example of an attempt that won't compile:

    Code:
    #include <string>
    
    struct golf
    {
    	string fullname;
    	int handicap;
    };
    
    void setgolf(golf & g, const string name, int hc);
    int setgolf(golf & g);
    void handicap(golf & g, int hc);
    void showgolf(const golf & g);
    The #include directive may not belong there, but what triggers the error is just using the string variable in defining my structure. It just seems to me that there has to be a way to use non-primitive data-types in your header files, but I'm not getting it right, obviously.

    Just as point of info, this goes with ch. 9, ex. 2 in Prata, C++ Primer Plus.

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    C++ has never had a string. It does have a std::string, however.

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    242
    While it may be stating the obvious, I should perhaps add that this is the complete file golf.h, which is the prototype file for golf.cpp, where the functions are defined. And both then link to another file (called pe9-2.cpp just because of exercise sequence, but name doesn't matter).

    I suppose I should also have created an include guard, but it shouldn't really matter with respect to the current issue.

  4. #4
    Registered User
    Join Date
    May 2009
    Posts
    242
    Ah, interesting. So does that mean that my code should work if I do either of the following:

    1) put in "using std::string" at the top and leaving out the #include <string> at the top.

    2) leave out the #include <string> (which just looks wrong to me, although it doesn't seem to be causing any error--but I'm not convinced that it's doing anything good either) and just substitute "std::string" in each instance where I've used the word "string".

  5. #5
    Registered User
    Join Date
    May 2009
    Posts
    242
    yep, throwing out the include and putting in "using std::string;" at the top made it compile.

    Haven't tested it for doing what I want, but I think it probably will.

    Thanks!

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Aisthesis View Post
    yep, throwing out the include and putting in "using std::string;" at the top made it compile.

    Haven't tested it for doing what I want, but I think it probably will.

    Thanks!
    Never, ever, ever, EVER put a using directive in a header file. NEVER.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  7. #7
    Registered User
    Join Date
    May 2009
    Posts
    242
    well, that's a using declaration, right? So, in this specific case, it just means that in any file linked to that header file, "string" is interpreted as "std::string".

    I'm not seeing exactly how that leads to such horrors in the long-run... ??

    Prata does say to "avoid" using DIRECTIVES in header files, but even there, he doesn't make it sound quite as taboo as you are suggesting...

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Aisthesis View Post
    well, that's a using declaration, right? So, in this specific case, it just means that in any file linked to that header file, "string" is interpreted as "std::string".
    Which means that any file which wants to declare a type called "string" is completely inoperable with that header file. In the worst case, it still compiles, but the type is silently wrong.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  9. #9
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    1. If you're using std::string in your header, you need to #include <string> in your header. Otherwise your code won't compile if you change the order of your #include statements in your .cpp file.

    2. Don't put using directives in header files for the reason brewbuck gave.
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  10. #10
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Prata does say to "avoid" using DIRECTIVES in header files, but even there, he doesn't make it sound quite as taboo as you are suggesting...
    In large code bases it is extremely taboo. Others who include your header bring in the entire namespace you brought into the header. In a cpp it's perfectly valid to use a using because your implementation file will not be included by anyone else - providing you have at least halfway intelligent programmers on your team. If someone does include your implementation file and it's not a template impl then you can smack them for being stupid.

  11. #11
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    So to sum up:
    Code:
    #include <string>
    
    struct golf
    {
    	std::string fullname;
    	int handicap;
    };
    
    ...

  12. #12
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Aisthesis, leave the include declaration as it was initially. That's not the source of your error and it is the right thing to do. You are including a standard library header file that declares the object you need to use. On this case, std::string.

    The change you need to make for your initial code to work is to prefix std:: to string. Since the string class is declared inside the namespace std, you need to call it with the std qualifier.

    Now, let's assume this bothers you because your golf struct declares a bunch of standard library types and you don't want (for some reason) to write std:: all over the place. That's just fine. You can use a typedef...

    Code:
    #include <string>
    
    struct golf
    {
        private:
            typedef std::string string;
        public:
    	string fullname;
    	int handicap;
    };
    It is declared private because this is merely an implementation shorthand. You don't want it to be accessed by users of your class.

    Another (probably better) solution is to create your own namespace:

    Code:
    #include <string>
    
    namespace mine {
    	using std::string;
    
    	struct golf
    	{
    		string fullname;
    		int handicap;
    	};
    }
    Probably better because the habit of creating and maintaining our own namespaces is a good thing since it is a powerful tool that allows us to curb name collision or better support the separation of interface and implementation.

    In any case here, despite you use a using declaration inside a header file, it is declared inside a namespace you control, and is only local to that namespace.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  13. #13
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    This has been bugging me... I don't think I gave a good advise here...

    Code:
    #include <string>
    
    namespace mine {
    	using std::string;
    
    	struct golf
    	{
    		string fullname;
    		int handicap;
    	};
    }
    You really don't want to do this. It's true you are lifting std::string inside a namespace you control. But there can be very real reasons for a user of your namespace to want to do:

    Code:
    using namespace mine;
    At function scope for instance, or when merging your namespace with their own. On the other hand the using declaration is being made at too much of a higher scope. Right at mine::. This isn't correct. You will be exposing std::string too much. Perhaps even to areas of the namespace mine where it isn't necessary or desirable.

    Consider the typedef approach the more correct.

    Anyone care to comment?
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Mario F.
    Anyone care to comment?
    In C++ Coding Standards, Sutter and Alexandrescu recommend against using directives and using declaration in namespace scope in a header file, and that recommendation includes avoiding what you suggested about a using declaration within a namespace.

    As a demonstration, they provide this code snippet, with the critical question in a comment:
    Code:
    // snippet 1
    namespace A {
        int f(double);
    }
    
    // snippet 2
    namesapce B {
        using A::f;
        void g();
    }
    
    // snippet 3
    namespace A {
        int f(int);
    }
    
    // snippet 4
    void B::g() {
        f(1); // which overload is called?
    }
    They proceed to comment that:
    The dangerous thing happening here is that the using declaration takes a snapshot of whatever entities named f in namespace A have been seen by the time the using declaration is encountered. So, from within B, which overloads are visible depends on where these code snippets exist and in what order they are combined. (At this point, your internal "but order dependencies are evil!" klaxon should be blaring.) The second overload, f(int), would be a better match for the call f(1), but f(int) will be invisible to B::g if its declaration comes after the using declaration.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #15
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Yeah. That was my thought too. I couldn't be right.
    Thanks for the confirmation.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Header files and multiple definitions
    By sjweinberg in forum C++ Programming
    Replies: 16
    Last Post: 07-17-2009, 05:59 PM
  2. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  3. Using c++ standards
    By subdene in forum C++ Programming
    Replies: 4
    Last Post: 06-06-2002, 09:15 AM
  4. more header files
    By Unregistered in forum C++ Programming
    Replies: 2
    Last Post: 10-28-2001, 01:56 PM