'static const std::string' in a header file

M

Mathieu Malaterre

Hello,

This thread follow my previous one on the gcc mailing list. Basically I
-still- have a problem in my code. I define in a header file:

static const std::string foo = "bar";

Which not only seems to be a bad practice but also creates a bug on
MacOSX panther (gcc 3.3).


Could someone suggest me a better approach than this one. Knowing that
I need to have a const reference access to the string.

I tried the approach :

// header.H
extern const std::string foo;

//implementation.C
const std::string foo = "bar";

but this doesn't seems to work with VS6/7: error LNK2019: unresolved
external symbol ...

---------
Gabriel Dos Reis (from the gcc ML) proposed the following approach:

// header.H
const std::string& foo();

// implementation.C
const std::string& foo() {
static const std::string instance = "foo";
return instance;
}

Comments/suggestions very welcome.
Thanks,
Mathieu
 
V

Victor Bazarov

Mathieu said:
This thread follow my previous one on the gcc mailing list.
Basically I -still- have a problem in my code. I define in a header file:

static const std::string foo = "bar";

Which not only seems to be a bad practice but also creates a bug on
MacOSX panther (gcc 3.3).


Could someone suggest me a better approach than this one. Knowing
that I need to have a const reference access to the string.

I tried the approach :

// header.H
extern const std::string foo;

//implementation.C
const std::string foo = "bar";

but this doesn't seems to work with VS6/7: error LNK2019: unresolved
external symbol ...

That's rather strange. Are you sure you're linking all the necessary
modules together? Does your 'implementation.C' include 'header.H'? The
compiler needs to know that the 'foo' you define in 'implementation.C' is
the one other modules refer to. For that 'foo' must be declared 'extern'
as well. To fix that either include 'header.H' in 'implementation.C' or
change the statement in 'implementation.C' to read

extern const std::string foo = "bar";
---------
Gabriel Dos Reis (from the gcc ML) proposed the following approach:

// header.H
const std::string& foo();

// implementation.C
const std::string& foo() {
static const std::string instance = "foo";
return instance;
}

The biggest difference between this and the other approach is that 'foo'
here is "extern" by default because it's a function. For a const object
you must specify 'extern' yourself.

Victor
 
M

Mathieu Malaterre

Victor said:
That's rather strange. Are you sure you're linking all the necessary
modules together? Does your 'implementation.C' include 'header.H'? The
compiler needs to know that the 'foo' you define in 'implementation.C' is
the one other modules refer to. For that 'foo' must be declared 'extern'
as well. To fix that either include 'header.H' in 'implementation.C' or
change the statement in 'implementation.C' to read

extern const std::string foo = "bar";

Doesn't seems to make any change (*). The library is building fine
though. It's just that as soon as I build an executable that link to the
lib I get the error...

(*)
BuildUpDicomDir.cxx
Linking...
Creating library C:\Dashboards\My
Tests\gdcmVS60\bin\Debug/BuildUpDicomDir.lib and object C:\Dashboards\My
Tests\gdcmVS60\bin\Debug/BuildUpDicomDir.exp
BuildUpDicomDir.obj : error LNK2001: unresolved external symbol "class
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> > const gdcm::GDCM_UNKNOWN"
(?GDCM_UNKNOWN@gdcm@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@B)
C:\Dashboards\My Tests\gdcmVS60\bin\Debug/BuildUpDicomDir.exe : fatal
error LNK1120: 1 unresolved externals
Error executing link.exe.


Thanks,
Mathieu
Ps: I'll try the 'function' approach and let you know.
 
A

Alf P. Steinbach

* Victor Bazarov:
To fix that either include 'header.H' in 'implementation.C' or
change the statement in 'implementation.C' to read

extern const std::string foo = "bar";

This will a generate multiple definition error when the header
is included in more than one compilation unit.

Instead just do

std::string const foo = "bar";

which, however, doesn't guarantee a single instance.


That's one possible work-around if you want to be guaranteed _one_
and only one instance of the string, except you probably don't want
the implementation file compiled as 'C'. Nitpick: it will be more
efficient to place the instance outside the function. As it is
every function call has to check whether it's been constructed.

Another work-around is to use a template class.

#include <string>

struct Dummy {};
template<typename T>
struct Strings_
{
static std::string const foo;
};
template<typename T> std::string const Strings_<T>::foo = "foo";
typedef Strings_<Dummy> Strings;

int main()
{
std::string s = Strings::foo;
}

That's more to write but most efficient in terms of generated code.
 
V

Victor Bazarov

Alf said:
* Victor Bazarov:



This will a generate multiple definition error when the header
is included in more than one compilation unit.

No, it won't. If the statement in the _header_ does not have the
initialiser, and has the 'extern', then it's not a definition.
Instead just do

std::string const foo = "bar";

which, however, doesn't guarantee a single instance.

Exactly. So, don't.

Victor
 
A

Alf P. Steinbach

* Victor Bazarov:
No, it won't. If the statement in the _header_ does not have the
initialiser, and has the 'extern', then it's not a definition.

Sorry, I misunderstood what you wrote.

Another way to achieve the same is to make sure the header file is
included in the implementation file.

I just assumed that and therefore misread what you wrote.
 
M

Mathieu Malaterre

BuildUpDicomDir.cxx
Linking...
Creating library C:\Dashboards\My
Tests\gdcmVS60\bin\Debug/BuildUpDicomDir.lib and object C:\Dashboards\My
Tests\gdcmVS60\bin\Debug/BuildUpDicomDir.exp
BuildUpDicomDir.obj : error LNK2001: unresolved external symbol "class
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> > const gdcm::GDCM_UNKNOWN"
(?GDCM_UNKNOWN@gdcm@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@B)

C:\Dashboards\My Tests\gdcmVS60\bin\Debug/BuildUpDicomDir.exe : fatal
error LNK1120: 1 unresolved externals
Error executing link.exe.

I am a complete moron I forgot about the __declspec( dllexport )

Sorry for the noise, and thanks for your help.

Mathieu
 
M

Mathieu Malaterre

Another work-around is to use a template class.

#include <string>

struct Dummy {};
template<typename T>
struct Strings_
{
static std::string const foo;
};
template<typename T> std::string const Strings_<T>::foo = "foo";
typedef Strings_<Dummy> Strings;

int main()
{
std::string s = Strings::foo;
}

That's the exact same problem. It doesn't work on MacOSX Panther because
of the way file-scope objects in dylibs get initialized.

Mathieu
 
A

Alf P. Steinbach

* Mathieu Malaterre:
That's the exact same problem. It doesn't work on MacOSX Panther because
of the way file-scope objects in dylibs get initialized.

Is Panther a C++ compiler in addition to being an operating system version?

If the above doesn't work then you have a non-comforming C++ implementation,
or you're doing something outside the scope of standard C++, or both.

Try to be more precise.
 
M

Mathieu Malaterre

Alf said:
* Mathieu Malaterre:



Is Panther a C++ compiler in addition to being an operating system version?

If the above doesn't work then you have a non-comforming C++ implementation,
or you're doing something outside the scope of standard C++, or both.

Try to be more precise.

I am just quoting a mail from:

http://gcc.gnu.org/ml/gcc/2005-01/msg00505.html

This is completely out of my scope of expertise. I only know that you
have to be carefull with global object that doesn't gets properly
initialized before its first use. And Mac-O file format have a notion of
lazy data constructor.

That's all I know

Hope this answer your question,
Mathieu
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top