const/define -- efficiency for simple integrals

  • Follow


Is there any difference in efficiency between (at global scope):

static const int MAX_CHAR (1024);

and

#define MAX_CHAR 1024

I'm wondering about both time and space efficiency.  I can take the
address of the static const int, so surely it must take up space.  The
define is 'just a number' so doesn't have to take up any space.  Is
this right?


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply studennett (5) 4/13/2006 6:52:27 AM

"studennett" <studennett@hotmail.com> wrote in message
news:1144845365.832751.189250@j33g2000cwa.googlegroups.com...
: Is there any difference in efficiency between (at global scope):
:
: static const int MAX_CHAR (1024);
:
: and
:
: #define MAX_CHAR 1024
:
: I'm wondering about both time and space efficiency.  I can take the
: address of the static const int, so surely it must take up space.

Space will have to be allocated *only* if you take the address.
[ I am not sure this is formally required by the standard,
   but it is the expectation / typical implementation. ]

: The define is 'just a number' so doesn't have to take up any space.
: Is this right?

The key property of the #define is that it will escape any scoping
rules - i.e. you cannot encapsulate it within a namespace or class
scope.
If you are concerned about the constant taking space (you really
don't need to be), or face problems with legacy compilers, a much
better solution is to use an enum-constant:

   enum {
     max_char = 1024
   };


hth-Ivan
-- 
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form




      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Ivan 4/14/2006 11:36:08 AM


Hello,
If it is possible, In C++ constant value is not stored in memory.
Therefore time space efficieny will be the same as for #define (for
this example). But const is safer...

(Word static mean that variable will be viewed only in file scope.)

Best regards
Mariusz


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply MariuszK 4/14/2006 11:43:54 AM

studennett wrote:
> Is there any difference in efficiency between (at global scope):
>
> static const int MAX_CHAR (1024);
>
> and
>
> #define MAX_CHAR 1024
>
> I'm wondering about both time and space efficiency.  I can take the
> address of the static const int, so surely it must take up space.  The
> define is 'just a number' so doesn't have to take up any space.  Is
> this right?

No. You're assuming that it also takes up space if you / don't / take
its
address. However, with modern compilers it's precisely the act of
taking
its address that forces it to take up space. If you don't, the linker
will
see it as an unused symbol and remove it (except in debug mode, in
which case the compiler usually leaves it for the debuggers use.)

HTH,
Michiel Salters


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Michiel 4/14/2006 11:48:50 AM

studennett wrote:
> Is there any difference in efficiency between (at global scope):

> static const int MAX_CHAR (1024);

> and

> #define MAX_CHAR 1024

> I'm wondering about both time and space efficiency.  I can
> take the address of the static const int, so surely it must
> take up space.  The define is 'just a number' so doesn't have
> to take up any space.  Is this right?

No.  With any reasonable compiler, both should be exactly
equivalent when used in the same way.

If you take the address of the static const int, the compiler
probably will have to generate an instance of the variable.  If
you need the address of the macro, you will have to define an
instance of the correct type too, so there is no difference
there either.

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                    Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 4/14/2006 11:55:12 AM

studennett wrote:
> Is there any difference in efficiency between (at global scope):

> static const int MAX_CHAR (1024);

> and

> #define MAX_CHAR 1024

> I'm wondering about both time and space efficiency.  I can
> take the address of the static const int, so surely it must
> take up space.  The define is 'just a number' so doesn't have
> to take up any space.  Is this right?

I just replied saying that there was no difference, but it
occurs to me that there is one case where there might be a
difference: when passing the value to a const reference (e.g. to
vector<int>::push_back).  This is effectively the same thing as
taking its address -- it will force an instance of the static
const int; in the case of the #define, most of the compilers
I've seen will generate a temporary variable, initialize it, and
pass its address.  So in this case, the static const int will
normally be faster and result in less space used.

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                    Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 4/14/2006 11:56:07 AM

studennett wrote:
> Is there any difference in efficiency between (at global scope):
>
> static const int MAX_CHAR (1024);
>
> and
>
> #define MAX_CHAR 1024
>
> I'm wondering about both time and space efficiency.  I can take the
> address of the static const int, so surely it must take up space.  The
> define is 'just a number' so doesn't have to take up any space.  Is
> this right?

Implementation dependent. The static const int must take up space IF
you take its address, yes. If you don't, it doesn't: you can't tell the
difference, so the "as if" rule applies.

It's much like function inlining - just because you can take the
address of a function, that doesn't mean the compiler can't inline it.
It just means that IF you take its address, the compiler ALSO has to
lay down a non-inlined copy to give you a pointer to.

cheers
Mike


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Mike 4/14/2006 11:59:19 AM


"studennett" <studennett@hotmail.com> writes:



> Is there any difference in efficiency between (at global scope):

>

> static const int MAX_CHAR (1024);

>

> and

>

> #define MAX_CHAR 1024

>

> I'm wondering about both time and space efficiency.



That former is more time efficient. Not execution time, but

developement time. Because variables are much better behaved than

macros.





> I can take the address of the static const int, so surely it must

> take up space.



It only has to take up space *if* you do something that requires it,

such as taking its address.



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Thomas 4/14/2006 12:01:25 PM

Hello studennett,

> Is there any difference in efficiency between (at global scope):
>
> static const int MAX_CHAR (1024);
>
> and
>
> #define MAX_CHAR 1024

> I'm wondering about both time and space efficiency.  I can take the
> address of the static const int, so surely it must take up space.  The
> define is 'just a number' so doesn't have to take up any space.  Is
> this right?

Almost. Yes, of course, simple number (define) is more fast to  
process as
far as it doesn't include operations
with pointers. HOWEVER, most of today's compiler optimize first  
option really
good and advantages you gain when
you aren't using #define are nothing compare with the advantages of  
"normal"
consts.
Thanks!



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Aleksander 4/14/2006 1:37:12 PM

In article <1144845365.832751.189250
@j33g2000cwa.googlegroups.com>, studennett@hotmail.com
says...
> Is there any difference in efficiency between (at global scope):
>
> static const int MAX_CHAR (1024);
>
> and
>
> #define MAX_CHAR 1024
>
> I'm wondering about both time and space efficiency.  I can take the
> address of the static const int, so surely it must take up space.  The
> define is 'just a number' so doesn't have to take up any space.  Is
> this right?

It may be right, but usually isn't. At least with most
compilers, the variable will take up space ONLY if you
take its address. There may be a few other things that
would force it to take up space, but in a typical case
the output code will be identical either way.

-- 
     Later,
     Jerry.

The universe is a figment of its own imagination.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Jerry 4/14/2006 1:37:43 PM

studennett wrote:
> Is there any difference in efficiency between (at global scope):
>
> static const int MAX_CHAR (1024);
>
> and
>
> #define MAX_CHAR 1024
>
> I'm wondering about both time and space efficiency.  I can take the
> address of the static const int, so surely it must take up space.  The
> define is 'just a number' so doesn't have to take up any space.  Is
> this right?

If you use the address of the int then it must be allocated space. If
you dont take its address then the compiler can probably figure out
that it doesnt need to allocate space so you wont see it in the image
(I think the guarantee is even stronger inside a class). Of course with
the define you cant take its address.
Another alternative is an enum ...

regards
Andy Little


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kwikius 4/14/2006 1:38:13 PM

studennett wrote:
> Is there any difference in efficiency between (at global scope):
>
> static const int MAX_CHAR (1024);
>
> and
>
> #define MAX_CHAR 1024
>
> I'm wondering about both time and space efficiency.  I can take the
> address of the static const int, so surely it must take up space.  The
> define is 'just a number' so doesn't have to take up any space.  Is
> this right?

   This is wrong. If the address of a constant is not used in the
program, a trivial linker optimization will remove it from the final
program.
   One of the problems with '#define' is that once issued, it stays for
all the code, including the interfaces that are not yours. For example,
if the name MAX_CHAR appears in several places with different values,
it will be very difficult to use all the interfaces with their own
MAX_CHAR.
   If you use a MAX_CHAR as a 'const int' and put it into an appropriate
namespace, you wouldn't depend on others not using the same name for
their constants.

   BTW, '#define' is not C/C++, it's a preprocessor command. It makes
programs less readable.  Whenever you want to use a '#define', think
about using a constant/inlined function/template instead. In most cases
there will be the same result, with a more structured program.

   Michael


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Michael 4/14/2006 1:42:17 PM

> static const int MAX_CHAR (1024);
compiler can do more checks including type, scope.  the MAX_CHAR will
be stored in data segment so it always occupies the space of memory but
only once under the scope.

> #define MAX_CHAR 1024
compiler doesn't check the type. The value could be embedded in some
machine instructions on some platforms, and not occupy extra memory. In
this kind of scenario, it is efficient. If MAX_CHAR is not a part of
machine instructions, it could duplicately occupy the memory space
under the scope of blocks or functions so it is possible to take up
more memory space than the first way.

I think that there is less difference in efficiency between them for
most cases but C++ likes the first way that perhaps takes up less
memory space.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply dan2online 4/14/2006 4:04:25 PM

In article <1144931041.913652.111920@z34g2000cwc.googlegroups.com>, 
kanze <kanze@gabi-soft.fr> writes
>studennett wrote:
>> Is there any difference in efficiency between (at global scope):
>
>> static const int MAX_CHAR (1024);
>
>> and
>
>> #define MAX_CHAR 1024
>
>> I'm wondering about both time and space efficiency.  I can
>> take the address of the static const int, so surely it must
>> take up space.  The define is 'just a number' so doesn't have
>> to take up any space.  Is this right?
>
>No.  With any reasonable compiler, both should be exactly
>equivalent when used in the same way.

Except that the pre-processor version invades scopes. That is one reason 
to use a different spelling for the two forms. Imagine that you had a 
header file that had

#define MAX_CHAR 1024

and a .cpp file that had somewhere (possibly in a namespace)

static int const MAX_CHAR(512);

Any conceivable time saving by using the pre-processor macro would be 
minute compared to the time wasted debugging the above code.

Do not use lower case letters in pre-processor identifiers and always 
use at least one in names.

In general concern with this kind of micro-optimisation is misplaced, 
the compiler will normally do an excellent job and except in rare cases, 
any loss of time during the lifetime of the program as an executable 
will be a small fraction of the programmer's time in attempting the 
optimisation.


-- 
Francis Glassborow      ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Francis 4/14/2006 4:51:47 PM

kwikius wrote:
  > studennett wrote:
  >> Is there any difference in efficiency between (at global scope):

  >> static const int MAX_CHAR (1024);

  >> and

  >> #define MAX_CHAR 1024

  >> I'm wondering about both time and space efficiency.  I can
  >> take the address of the static const int, so surely it must
  >> take up space.  The define is 'just a number' so doesn't have
  >> to take up any space.  Is this right?

  > If you use the address of the int then it must be allocated
  > space. If you dont take its address then the compiler can
  > probably figure out that it doesnt need to allocate space so
  > you wont see it in the image (I think the guarantee is even
  > stronger inside a class). Of course with the define you cant
  > take its address.

You can't explicitly take its address.  You can still pass it as
a const reference, and the compiler will have to take its
address.

If you use the first form, you are guaranteed that the there
will be only one copy, since the language requires that the
address always be the same.  If you use the #define, there's no
such guarantee, and you may end up with multiple copies, or
temporary copies which are reinitialized each time around.

The upshot of it all is that the clean solution is also the most
efficient one in terms of space and runtime.

-- 
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient�e objet/
                    Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France +33 (0)1 30 23 00 34

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply James 4/15/2006 12:10:49 PM

Francis Glassborow wrote:
> In article <1144931041.913652.111920@z34g2000cwc.googlegroups.com>,
> kanze <kanze@gabi-soft.fr> writes
>> studennett wrote:
>>> Is there any difference in efficiency between (at global scope):
>>> static const int MAX_CHAR (1024);
>>> and
>>> #define MAX_CHAR 1024
>>> I'm wondering about both time and space efficiency.  I can
>>> take the address of the static const int, so surely it must
>>> take up space.  The define is 'just a number' so doesn't have
>>> to take up any space.  Is this right?
>> No.  With any reasonable compiler, both should be exactly
>> equivalent when used in the same way.

> Except that the pre-processor version invades scopes.

This may surprise you, but I'm aware of that:-).  I sort of
mis-phrased my answer -- what I meant to say is that with any
reasonable compiler, there will be no difference in the
generated code.

Except that immediately after posting, I realized that that was
wrong.  Because in practice, the compiler often has to generate
an address for the constant: in the const int form, that is no
problem but in the #define form, the compiler must do more work.
The result is that the #define form will probably result in
larger and slower code.  (Of course, I can't image the
difference being significant in any real application.)

> That is one reason to use a different spelling for the two
> forms. Imagine that you had a header file that had

> #define MAX_CHAR 1024
>
> and a .cpp file that had somewhere (possibly in a namespace)

> static int const MAX_CHAR(512);

> Any conceivable time saving by using the pre-processor macro
> would be minute compared to the time wasted debugging the
> above code.

What time wasted debugging it.  I'd just throw it out and start
over:-).

> Do not use lower case letters in pre-processor identifiers and
> always use at least one in names.

For example.  (It's as good a rule as any, and you do need some
rule.  I also insist that preprocessor names be at least three
characters long, to avoid conflicts with simple one letter
typenames.)

> In general concern with this kind of micro-optimisation is
> misplaced, the compiler will normally do an excellent job and
> except in rare cases, any loss of time during the lifetime of
> the program as an executable will be a small fraction of the
> programmer's time in attempting the optimisation.

I really should have cut the above, but it is so accurate that
it can't be repeated too often.

-- 
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France +33 (0)1 30 23 00 34

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply James 4/15/2006 8:09:11 PM

Michael Tiomkin wrote:
>    BTW, '#define' is not C/C++, it's a preprocessor command. It makes
> programs less readable. 

A technical nit: #define is a preprocessor directive (rather
than a "command") as it is part of both the C and the C++
programming languages as defined by their respective standards.

(That said, there is a useful distinction between those parts
of the language that are implemented in "the preprocessor" and
those which happen after conversion of preprocessor tokens to
"real" tokens.  It's just that both are part of C++, and of C.)

> Whenever you want to use a '#define', think
> about using a constant/inlined function/template instead. In most cases
> there will be the same result, with a more structured program.
> 
>    Michael

True; good uses for the preprocessor are reasonably rare,
particularly if we ignore #ifndef guards around header files.

-- James

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply James 4/15/2006 8:25:24 PM

James Kanze wrote:
> kwikius wrote:

>   > If you use the address of the int then it must be allocated
>   > space. If you dont take its address then the compiler can
>   > probably figure out that it doesnt need to allocate space so
>   > you wont see it in the image (I think the guarantee is even
>   > stronger inside a class). Of course with the define you cant
>   > take its address.
>
> You can't explicitly take its address.  You can still pass it as
> a const reference, and the compiler will have to take its
> address.
>
> If you use the first form, you are guaranteed that the there
> will be only one copy, since the language requires that the
> address always be the same.  If you use the #define, there's no
> such guarantee, and you may end up with multiple copies, or
> temporary copies which are reinitialized each time around.
>
> The upshot of it all is that the clean solution is also the most
> efficient one in terms of space and runtime.

Actually I remember that use of static const ints inside classes caused
 problems and so I switched to using enums. Below is an example that
shows the problem in gcc 4.0( and probably other gcc versions) when
S::value is defined as an static const int , but disappears if its
defined as an enum. Note that the code links fine either way in VC7.1,
the other compiler tested. I have no idea who is correct.

#include <iostream>
struct S{
 #if(1)
    static int const value =1;
#else
   enum{value =1};
#endif
};

int f( const int & n){return n;}

int main()
{
   int n = f(S::value);
    std::cout << n << '\n';
}

When S::value is a static const int the gcc linker complains:

test.o:test.cpp:(.text+0x27): undefined reference to `S::value'
collect2: ld returned 1 exit status

regards
Andy Little


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kwikius 4/15/2006 8:36:58 PM

kwikius wrote:
>
> #include <iostream>
> struct S{
>  #if(1)
>     static int const value =1;
> #else
>    enum{value =1};
> #endif
> };
>
> int f( const int & n){return n;}
>
> int main()
> {
>    int n = f(S::value);
>     std::cout << n << '\n';
> }
>
> When S::value is a static const int the gcc linker complains:
>
> test.o:test.cpp:(.text+0x27): undefined reference to `S::value'
> collect2: ld returned 1 exit status
>
I am not quite sure about the reason, but I noticed that if you
initialize your constant outside the class:

const int S::value = 1 ;

then the error gcc does not complain anymore...

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Vincent 4/17/2006 10:58:37 AM

kwikius wrote:
> James Kanze wrote:
>> kwikius wrote:

>>   > If you use the address of the int then it must be
>>   > allocated space. If you dont take its address then the
>>   > compiler can probably figure out that it doesnt need to
>>   > allocate space so you wont see it in the image (I think
>>   > the guarantee is even stronger inside a class). Of course
>>   > with the define you cant take its address.

>> You can't explicitly take its address.  You can still pass it
>> as a const reference, and the compiler will have to take its
>> address.

>> If you use the first form, you are guaranteed that the there
>> will be only one copy, since the language requires that the
>> address always be the same.  If you use the #define, there's
>> no such guarantee, and you may end up with multiple copies,
>> or temporary copies which are reinitialized each time around.

>> The upshot of it all is that the clean solution is also the
>> most efficient one in terms of space and runtime.

> Actually I remember that use of static const ints inside
> classes caused problems and so I switched to using enums.
> Below is an example that shows the problem in gcc 4.0( and
> probably other gcc versions) when S::value is defined as an
> static const int , but disappears if its defined as an enum.
> Note that the code links fine either way in VC7.1, the other
> compiler tested. I have no idea who is correct.

G++.  But I think that the error is in fact undefined behavior,
so no compiler diagnostic is involved.

> #include <iostream>
> struct S{
>  #if(1)
>     static int const value =1;

Note that this is still a declaration, even though an
initialization value is present.  Formally, a definition is
required.

> #else
>    enum{value =1};
> #endif
> };

> int f( const int & n){return n;}

And to call this function, the compiler will have to take the
address of the object.

> int main()
> {
>    int n = f(S::value);
>     std::cout << n << '\n';
> }

> When S::value is a static const int the gcc linker complains:

> test.o:test.cpp:(.text+0x27): undefined reference to
> `S::value' collect2: ld returned 1 exit status

Which is perfectly acceptable.  (In the case of undefined
behavior, anything the compiler does is "acceptable".  Although
from a quality of implementation point of view -- I would expect
either a diagnostic, at the latest at link time, or that the
code work.)

Try defining the variable in one (and only one) translation
unit, e.g.:

     int const S::value ;

(Note that since the declaration has an initialization value, no
initialization should be given here.)

-- 
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France +33 (0)1 30 23 00 34

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply James 4/17/2006 8:39:56 PM

"Vincent Poinot" <vincent.use-my-last-name-here@wanadoo.fr> skrev i 
meddelandet news:44421b6e$0$20184$8fcfb975@news.wanadoo.fr...
> kwikius wrote:
>>
>> #include <iostream>
>> struct S{
>>  #if(1)
>>     static int const value =1;
>> #else
>>    enum{value =1};
>> #endif
>> };
>>
>> int f( const int & n){return n;}
>>
>> int main()
>> {
>>    int n = f(S::value);
>>     std::cout << n << '\n';
>> }
>>
>> When S::value is a static const int the gcc linker complains:
>>
>> test.o:test.cpp:(.text+0x27): undefined reference to `S::value'
>> collect2: ld returned 1 exit status
>>

To pass by reference, you need an object to pass. As it is just 
declared, but never defined, there is no object.

Now, you might wonder why you want to pass a constant by reference 
anyway, but that is another question.  :-)

> I am not quite sure about the reason, but I noticed that if you
> initialize your constant outside the class:
>
> const int S::value = 1 ;

There you have your object, and the linker will find it.


Bo Persson



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Bo 4/17/2006 8:41:53 PM

Vincent Poinot wrote:
> kwikius wrote:
> >
> > #include <iostream>
> > struct S{
> >  #if(1)
> >     static int const value =1;
> > #else
> >    enum{value =1};
> > #endif
> > };
> >
> > int f( const int & n){return n;}
> >
> > int main()
> > {
> >    int n = f(S::value);
> >     std::cout << n << '\n';
> > }
> >
> > When S::value is a static const int the gcc linker complains:
> >
> > test.o:test.cpp:(.text+0x27): undefined reference to `S::value'
> > collect2: ld returned 1 exit status
> >
> I am not quite sure about the reason, but I noticed that if you
> initialize your constant outside the class:
>
> const int S::value = 1 ;
>
> then the error gcc does not complain anymore...

The problem is in order for function f()'s const reference parameter to
bind to S::value, S::value must have allocated storage. When passing an
enum instead of S::value the compiler allocates the necessary storage
itself, in the form of a temporary which is then bound to the const
reference.

A better solution than allocating storage for S::value is to change the
declaration of f() to accept an int parameter by value. An int
parameter passed by value is certain to be more efficient than passing
a const reference to an int. There is in fact simply no reason for f to
be declared as it is. And without the const reference parameter, f()
will accept S::value as a parameter without requiring that it have any
allocated storage.

Greg


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Greg 4/17/2006 8:46:40 PM

Vincent Poinot wrote:
> kwikius wrote:
> >
> > #include <iostream>
> > struct S{
> >  #if(1)
> >     static int const value =1;
> > #else
> >    enum{value =1};
> > #endif
> > };
> >
> > int f( const int & n){return n;}
> >
> > int main()
> > {
> >    int n = f(S::value);
> >     std::cout << n << '\n';
> > }
> >
> > When S::value is a static const int the gcc linker complains:
> >
> > test.o:test.cpp:(.text+0x27): undefined reference to `S::value'
> > collect2: ld returned 1 exit status
> >
> I am not quite sure about the reason, but I noticed that if you
> initialize your constant outside the class:
>
> const int S::value = 1 ;
>
> then the error gcc does not complain anymore...
I think you'd get an error with that, because you have defined the
value of value twice. It should be just const int S::value;

The language does actually require that you do this. However, I have
noticed that several compilers / linkers seem to work quite happily if
you don't do this (actually, it was a nasty shock when we used one that
required you to do this - quite a lot of code broke).

It seems to me that this restriction could be withdrawn, although it
would require facilities in the linker of the sort that are needed for
template instantiation. The compiler could generate an instance of
S::value every time S::value was potentially used, and the linker could
then throw away all but one.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply ThosRTanner 4/17/2006 8:51:04 PM

Greg Herlihy wrote:
  > Vincent Poinot wrote:
  >> kwikius wrote:
  >>> #include <iostream>
  >>> struct S{
  >>>  #if(1)
  >>>     static int const value =1;
  >>> #else
  >>>    enum{value =1};
  >>> #endif
  >>> };

  >>> int f( const int & n){return n;}

      [...]
  > A better solution than allocating storage for S::value is to
  > change the declaration of f() to accept an int parameter by
  > value. An int parameter passed by value is certain to be more
  > efficient than passing a const reference to an int. There is
  > in fact simply no reason for f to be declared as it is.

This is true, but then, it isn't very reasonable to call a
function f, either.  I would imagine that the posted code is a
simplification of the actual code, and the f is just a place
holder for some more complicated function.  Say
std::vector<int>::push_back() (which does take a const int&).

  > And without the const reference parameter, f() will accept
  > S::value as a parameter without requiring that it have any
  > allocated storage.

Typically, in any case.  I"m not sure what the standard requires
here -- whether it is required to work, or whether it is
undefined behavior which in practice always works.  It really
doesn't matter -- an integral constant that can't be
push_back'ed into a vector<int> is not a very user friendly
beast, and I would make it a rule to always provide the
definition.

-- 
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient�e objet/
                    Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France +33 (0)1 30 23 00 34

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply James 4/18/2006 11:17:18 AM

James Kanze wrote:
> kwikius wrote:

> > When S::value is a static const int the gcc linker complains:
>
> > test.o:test.cpp:(.text+0x27): undefined reference to
> > `S::value' collect2: ld returned 1 exit status
>
> Which is perfectly acceptable.  (In the case of undefined
> behavior, anything the compiler does is "acceptable".  Although
> from a quality of implementation point of view -- I would expect
> either a diagnostic, at the latest at link time, or that the
> code work.)
>
> Try defining the variable in one (and only one) translation
> unit, e.g.:
>
>      int const S::value ;
>
> (Note that since the declaration has an initialization value, no
> initialization should be given here.)

Ah Ha! ...That does indeed solve the problem and works on both
compilers, however the problem occurred in what was meant to be a
header only library and therefore that solution would have an impact in
terms of ease of use of the library. Note that the enum solution works
very nicely in this case, but does have its own problems, requiring for
example, to be explicitly static cast to an int ( in gcc ), to prevent
errors in some compile time math operations, the exact circumstances of
which I now forget ( struct1::enuma < struct2::enumb ??).

regards
Andy Little


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kwikius 4/18/2006 11:32:12 PM

Greg Herlihy wrote:

> > kwikius wrote:
> > > int f( const int & n){return n;}

> A better solution than allocating storage for S::value is to change the
> declaration of f() to accept an int parameter by value. An int
> parameter passed by value is certain to be more efficient than passing
> a const reference to an int. There is in fact simply no reason for f to
> be declared as it is. And without the const reference parameter, f()
> will accept S::value as a parameter without requiring that it have any
> allocated storage.

FWIW The problem was brought up by a user of my pqs library
http://tinyurl.com/7m5l8 .(Currently in the review queue hoping to
become part of the boost libraries http://www.boost.org )  IOW I had no
control of how the function was defined... maybe nor did he.

regards
Andy Little


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kwikius 4/18/2006 11:32:34 PM

kwikius wrote:
> James Kanze wrote:
> > kwikius wrote:
>
> >   > If you use the address of the int then it must be allocated
> >   > space. If you dont take its address then the compiler can
> >   > probably figure out that it doesnt need to allocate space so
> >   > you wont see it in the image (I think the guarantee is even
> >   > stronger inside a class). Of course with the define you cant
> >   > take its address.
> >
> > You can't explicitly take its address.  You can still pass it as
> > a const reference, and the compiler will have to take its
> > address.
> >
> > If you use the first form, you are guaranteed that the there
> > will be only one copy, since the language requires that the
> > address always be the same.  If you use the #define, there's no
> > such guarantee, and you may end up with multiple copies, or
> > temporary copies which are reinitialized each time around.
> >
> > The upshot of it all is that the clean solution is also the most
> > efficient one in terms of space and runtime.
>
> Actually I remember that use of static const ints inside classes caused
>  problems and so I switched to using enums. Below is an example that
> shows the problem in gcc 4.0( and probably other gcc versions) when
> S::value is defined as an static const int , but disappears if its
> defined as an enum. Note that the code links fine either way in VC7.1,
> the other compiler tested. I have no idea who is correct.
>
> #include <iostream>
> struct S{
>  #if(1)
>     static int const value =1;
> #else
>    enum{value =1};
> #endif
> };
>
> int f( const int & n){return n;}
>
> int main()
> {
>    int n = f(S::value);
>     std::cout << n << '\n';
> }
>
> When S::value is a static const int the gcc linker complains:
>
> test.o:test.cpp:(.text+0x27): undefined reference to `S::value'
> collect2: ld returned 1 exit status
>
> regards
> Andy Little

I tried your code in comeau, one of the more standard compliant
compilers, it compiled the snippet without any problem in strict error
mode. But since comeau does not link (and some of the intricacies in
this program only arises during link time), there is still question
unanswered.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Fei 5/2/2006 10:38:25 AM

26 Replies
115 Views

(page loaded in 0.2 seconds)

Similiar Articles:


















7/16/2012 9:22:40 PM


Reply: