Acceptable to "const" a parameter in the definition but not in thedeclaration?

Discussion in 'C++' started by jl_post@hotmail.com, Jun 8, 2010.

  1. Guest

    Hi,

    I'm a big fan of the "const" keyword for several reasons. I don't
    want to get too deep in my reasons, but one place I'll use them is in
    code like this:

    const int numToUse = getSomeNumber(...);

    Since I declared numToUse as const, it's clear to the maintainer that
    numToUse will not change for the rest of its scope, nor is it supposed
    to change (preventing a maintainer from accidentally changing it).

    At any rate, sometimes I create a function/method that has a
    signature like the following:

    void f(int arg1);

    But for my example, arg1 is essentially a constant, since it never
    changes. So I COULD declare f() as:

    void f(const int arg1);

    but that const is basically unneeded for the maintainer who only needs
    to know the signature of f(). However, putting the const keyword in
    tells whoever looks at the definition of f() that arg1 is never
    supposed to change.

    (Note that I am not passing by reference -- only by value.)

    So the advantage of putting const in is that the maintainer who
    reads the definition of f() can tell that arg1 is never supposed to
    change in f(). But this information is unimportant to the maintainer
    who treats f() as a "black-box" -- to him/her it makes no difference
    if arg1 (which is passed by value) is changed in f(), so seeing arg1
    declared as const is of no help at all.

    Playing around with this, I discovered that I can declare arg1 as
    const in the definition, like this:

    void f(const int arg1) { ... }

    while not declaring arg1 as const in the declaration/signature/
    prototype, like this:

    void f(int arg1);

    The compiler will compile this just fine, despite that "const" is not
    in both lines. (I tried this on Visual C++, g++ on Win32, and g++ on
    Linux.)

    If you'd like to see a full working program that illustrates what
    I'm talking about, here is one:


    #include <iostream>

    void f(int arg1);

    int main(int argc, char ** argv)
    {
    f(77);

    return 0;
    }

    void f(const int arg1)
    {
    std::cout << "arg1 = " << arg1 << std::endl;
    }


    So my question is: Is this an acceptable thing to do (as far as the
    C++ language specifications are concerned)?

    (Just because it works on all compilers I've tried it on so far
    doesn't necessarily mean it's allowed in the standard language, so I'd
    like to know for sure if it's a legal thing to do.)

    Being able to do this is good in that the maintainers of the
    function can see what passed-in arguments are never supposed to
    change, while the other maintainers can treat the function as a black-
    box and not need to see which passed-in-by-value arguments are const.

    Thanks.

    -- Jean-Luc
     
    , Jun 8, 2010
    #1
    1. Advertising

  2. Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    On 6/8/2010 11:48 AM, wrote:
    > I'm a big fan of the "const" keyword for several reasons. I don't
    > want to get too deep in my reasons, but one place I'll use them is in
    > code like this:
    >
    > const int numToUse = getSomeNumber(...);
    >
    > Since I declared numToUse as const, it's clear to the maintainer that
    > numToUse will not change for the rest of its scope, nor is it supposed
    > to change (preventing a maintainer from accidentally changing it).
    >
    > At any rate, sometimes I create a function/method that has a
    > signature like the following:
    >
    > void f(int arg1);
    >
    > But for my example, arg1 is essentially a constant, since it never
    > changes. So I COULD declare f() as:
    >
    > void f(const int arg1);
    >
    > but that const is basically unneeded for the maintainer who only needs
    > to know the signature of f(). However, putting the const keyword in
    > tells whoever looks at the definition of f() that arg1 is never
    > supposed to change.
    >
    > (Note that I am not passing by reference -- only by value.)
    >
    > So the advantage of putting const in is that the maintainer who
    > reads the definition of f() can tell that arg1 is never supposed to
    > change in f(). But this information is unimportant to the maintainer
    > who treats f() as a "black-box" -- to him/her it makes no difference
    > if arg1 (which is passed by value) is changed in f(), so seeing arg1
    > declared as const is of no help at all.
    >
    > Playing around with this, I discovered that I can declare arg1 as
    > const in the definition, like this:
    >
    > void f(const int arg1) { ... }
    >
    > while not declaring arg1 as const in the declaration/signature/
    > prototype, like this:
    >
    > void f(int arg1);
    >
    > The compiler will compile this just fine, despite that "const" is not
    > in both lines. (I tried this on Visual C++, g++ on Win32, and g++ on
    > Linux.)
    >
    > If you'd like to see a full working program that illustrates what
    > I'm talking about, here is one:
    >
    >
    > #include<iostream>
    >
    > void f(int arg1);
    >
    > int main(int argc, char ** argv)
    > {
    > f(77);
    >
    > return 0;
    > }
    >
    > void f(const int arg1)
    > {
    > std::cout<< "arg1 = "<< arg1<< std::endl;
    > }
    >
    >
    > So my question is: Is this an acceptable thing to do (as far as the
    > C++ language specifications are concerned)?


    What is? The top-level const qualifiers for arguments or return value
    are ignored and do not contribute to the function type, so

    void f(int);

    and

    void f(int const);

    are two declarations of the same function.

    As to acceptability, do what your coding standard tells you. In our
    group if the function is declared in some way, you should be able to
    look for the declaration using textual search, which means we keep even
    the names of the arguments the same...

    > (Just because it works on all compilers I've tried it on so far
    > doesn't necessarily mean it's allowed in the standard language, so I'd
    > like to know for sure if it's a legal thing to do.)


    Yes.

    > Being able to do this is good in that the maintainers of the
    > function can see what passed-in arguments are never supposed to
    > change, while the other maintainers can treat the function as a black-
    > box and not need to see which passed-in-by-value arguments are const.


    In our neck of the woods we say, whatever floats your boat.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 8, 2010
    #2
    1. Advertising

  3. Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    * , on 08.06.2010 17:48:
    >
    > #include<iostream>
    >
    > void f(int arg1);
    >
    > int main(int argc, char ** argv)
    > {
    > f(77);
    >
    > return 0;
    > }
    >
    > void f(const int arg1)
    > {
    > std::cout<< "arg1 = "<< arg1<< std::endl;
    > }
    >
    >
    > So my question is: Is this an acceptable thing to do (as far as the
    > C++ language specifications are concerned)?


    It's standard-conforming, yes.

    However, only top level 'const' is disregarded for forming the function's type.

    E.g. 'int const' -> 'int', but not 'int const*' -> 'int*'.


    Cheers & hth.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach, Jun 8, 2010
    #3
  4. Jorgen Grahn Guest

    Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    On Tue, 2010-06-08, Alf P. Steinbach wrote:
    ....
    > However, only top level 'const' is disregarded for forming
    > the function's type.
    >
    > E.g. 'int const' -> 'int', but not 'int const*' -> 'int*'.


    Which is a slightly convoluted way of saying "only the things that are
    surely irrelevant to the interface are disregarded in the interface".

    When you use call-by-value, you couldn't care less if the callee
    modifies his copy of the value. Easy to remember, and makes good
    sense.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Jun 8, 2010
    #4
  5. Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    * Jorgen Grahn, on 08.06.2010 22:09:
    > On Tue, 2010-06-08, Alf P. Steinbach wrote:
    > ...
    >> However, only top level 'const' is disregarded for forming
    >> the function's type.
    >>
    >> E.g. 'int const' -> 'int', but not 'int const*' -> 'int*'.

    >
    > Which is a slightly convoluted way of saying "only the things that are
    > surely irrelevant to the interface are disregarded in the interface".


    That turns out to be a circular argument, because (see below) the 'const' is
    only irrelevant because of the current rules that it is disregarded...


    > When you use call-by-value, you couldn't care less if the callee
    > modifies his copy of the value. Easy to remember, and makes good
    > sense.


    Yes, easy to remember, but a bit misleading.

    Consider the translation of a function

    void foo( T v );

    to machine code, and in particular, for sizeof(T) > something, implementing the
    function in machine code as if it were declared as

    void foo( T* v );

    which in certain cases may reduce the argument passing from a large number of
    bytes to four or eight bytes.

    If there is possible aliasing, that some code invoked by foo (or perhaps
    executing in a separate thread) accesses the caller's actual argument, then this
    optimization is unsafe unless a copy of the actual argument is made. The copy
    can made at the call site or internally in foo. The latter was not uncommon in
    the old days, at least for Pascal compilers, because when foo does nothing with
    the argument but passing it on, then the copying can be avoided.

    Placing the copying at the call site, on the other hand, allows that copying to
    be elided when the compiler can prove that there's no aliasing and can assume
    that foo does not change the actual argument via the passed pointer. So this
    could be an optimization. But if the source code implementation of foo is e.g.

    void foo( T v ) { v = bar(); blahblah(); use( v ); }

    then, at least for local code generation, the code generated for foo would also
    have to copy v, resulting in potentially two copy operations per call (one at
    each call site and one inside foo) instead of just one: hardly an optimization!

    However, if a 'T const' in the declaration guaranteed a 'T const' in the
    definition, then the compiler could do this optimization, perhaps with some
    wording in the standard that you're in UB-land if you cast away the const.
    Because then the compiler could assume that foo would not modify the actual
    argument via the pointer. All it'd have to do would be to prove no aliasing for
    any particular call site, and then it could just pass a pointer with no copying.

    Essentially, any restriction enforced by the type system increases what is known
    and so may facilitate some optimization, not just correctness. ;-)

    And so also here.


    Cheers,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach, Jun 8, 2010
    #5
  6. Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    * Paavo Helde, on 09.06.2010 00:33:
    > "Alf P. Steinbach"<> wrote in
    > news:humcfr$7l7$-september.org:
    >
    > [...]
    >
    >> Placing the copying at the call site, on the other hand, allows that
    >> copying to be elided when the compiler can prove that there's no
    >> aliasing and can assume that foo does not change the actual argument
    >> via the passed pointer. So this could be an optimization. But if the
    >> source code implementation of foo is e.g.
    >>
    >> void foo( T v ) { v = bar(); blahblah(); use( v ); }
    >>
    >> then, at least for local code generation, the code generated for foo
    >> would also have to copy v, resulting in potentially two copy
    >> operations per call (one at each call site and one inside foo) instead
    >> of just one: hardly an optimization!
    >>
    >> However, if a 'T const' in the declaration guaranteed a 'T const' in
    >> the definition, then the compiler could do this optimization, perhaps
    >> with some wording in the standard that you're in UB-land if you cast
    >> away the const. Because then the compiler could assume that foo would
    >> not modify the actual argument via the pointer. All it'd have to do
    >> would be to prove no aliasing for any particular call site, and then
    >> it could just pass a pointer with no copying.

    >
    > If the compiler can prove the function does not modify the argument, it
    > can apply this optimization anyway, regardless of whether there is
    > 'const' present or not.


    That "if" is pretty big: with the rules that we have it would require whole
    program optimization and is not possible with dynamic libraries without
    introducing overhead (the opposite of optimization).

    Since the context has been lost, and you're arguing below is if the context was
    very different than what it actually was:

    The context for the above quote was whether a possible rationale for the current
    rules held water or not, and it did not hold water.


    > And about adding new UB in the language - I would have thought there is
    > already too much of that. Besides, such a change could break existing
    > code in very annoying ways.


    I discussed the rationale for the existing rules. I did not discuss changing the
    rules. In particular, I did not advocate introducing new UB.


    >> Essentially, any restriction enforced by the type system increases
    >> what is known and so may facilitate some optimization, not just
    >> correctness. ;-)

    >
    > Except the 'const' keyword in interfaces, which can be cast away legally
    > in most cases.


    It's unclear what you're referring to.


    > Banning const_cast would indeed resolve this problem,


    It's unclear what you're referring to.


    > but
    > would create many more instead.


    I did not propose or discuss "banning const_cast". With C++98 rules const_cast
    for an original const object is UB if you modify the result. The alternative
    rules I discussed would presumably have extended that to formal arguments.


    > I think I will stick to passing const references, it's just one more
    > character to type after all.


    That statement does not make sense to me, I'm sorry.


    Cheers,

    - Alf


    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach, Jun 8, 2010
    #6
  7. Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    * Fred Zwarts, on 09.06.2010 09:24:
    > <> wrote in message
    > news:
    >
    >> #include<iostream>
    >>
    >> void f(int arg1);
    >>
    >> int main(int argc, char ** argv)
    >> {
    >> f(77);
    >>
    >> return 0;
    >> }
    >>
    >> void f(const int arg1)
    >> {
    >> std::cout<< "arg1 = "<< arg1<< std::endl;
    >> }
    >>
    >>
    >> So my question is: Is this an acceptable thing to do (as far as the
    >> C++ language specifications are concerned)?

    >
    > Maybe,


    It is standard-conforming.


    > but I have to work with a compiler which does not accept it.


    Which compiler is that?


    Cheers,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach, Jun 9, 2010
    #7
  8. Fred Zwarts Guest

    Re: Acceptable to "const" a parameter in the definition but not in the declaration?

    "Alf P. Steinbach" <> wrote in message
    news:huo725$7c2$-september.org
    > * Fred Zwarts, on 09.06.2010 09:24:
    >> <> wrote in message
    >> news:
    >>
    >>> #include<iostream>
    >>>
    >>> void f(int arg1);
    >>>
    >>> int main(int argc, char ** argv)
    >>> {
    >>> f(77);
    >>>
    >>> return 0;
    >>> }
    >>>
    >>> void f(const int arg1)
    >>> {
    >>> std::cout<< "arg1 = "<< arg1<< std::endl;
    >>> }
    >>>
    >>>
    >>> So my question is: Is this an acceptable thing to do (as far as
    >>> the C++ language specifications are concerned)?

    >>
    >> Maybe,

    >
    > It is standard-conforming.
    >
    >
    >> but I have to work with a compiler which does not accept it.

    >
    > Which compiler is that?


    The OpenVMS C++ 6.5 compiler for Alpha processors.
    I known it is an old version, but it is something I have to live with.

    The code:

    int func (int);

    int func (const int i) {
    return i;
    }

    results in:

    %CXX-W-NOTQUACOMPREDEC, declaration is not qualifier compatible with
    "int func(int)" (declared at line 1)
    at line number 3 in file SCRATCH_ROOT:<KLAD>T.CPP;1

    This warning is issued even when the compiler runs in ANSI-standard mode.
    It should be noted that this warning can be suppressed with a compiler option.
     
    Fred Zwarts, Jun 10, 2010
    #8
  9. Öö Tiib Guest

    Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    On Jun 10, 10:55 am, "Fred Zwarts" <> wrote:
    >
    > The OpenVMS C++ 6.5 compiler for Alpha processors.
    > I known it is an old version, but it is something I have to live with.
    >
    > The code:
    >
    > int func (int);
    >
    > int func (const int i) {
    > return i;
    >
    > }
    >
    > results in:
    >
    > %CXX-W-NOTQUACOMPREDEC, declaration is not qualifier compatible with
    > "int func(int)" (declared at line 1)
    > at line number 3 in file SCRATCH_ROOT:<KLAD>T.CPP;1
    >
    > This warning is issued even when the compiler runs in ANSI-standard mode.
    > It should be noted that this warning can be suppressed with a compiler option.


    It should be also noted that compiler may issue diagnostics about
    everything that it finds rude, funny, outstanding or otherwise
    remarkable during compiling. If it does not entirely refuse to compile
    a piece of code that is valid by standard it is all OK. Alf has whole
    entry in his blog how to turn off sillywarnings (his term) of
    microsoft compilers.
     
    Öö Tiib, Jun 10, 2010
    #9
  10. Jorgen Grahn Guest

    Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    On Tue, 2010-06-08, Alf P. Steinbach wrote:
    > * Jorgen Grahn, on 08.06.2010 22:09:
    >> On Tue, 2010-06-08, Alf P. Steinbach wrote:
    >> ...
    >>> However, only top level 'const' is disregarded for forming
    >>> the function's type.
    >>>
    >>> E.g. 'int const' -> 'int', but not 'int const*' -> 'int*'.

    >>
    >> Which is a slightly convoluted way of saying "only the things that are
    >> surely irrelevant to the interface are disregarded in the interface".

    >
    > That turns out to be a circular argument, because (see below) the 'const' is
    > only irrelevant because of the current rules that it is disregarded...


    I was a bit too lazy to read your longer text carefully, but I suppose
    I'm relying on the traditional meaning of call-by-value here, the one
    you're taught in CS classes. *That* is what makes the const irrelevant
    to the caller. I don't see C++ moving away from call-by-value any time
    soon.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Jun 12, 2010
    #10
  11. Jorgen Grahn Guest

    Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    On Tue, 2010-06-08, Paavo Helde wrote:
    > "Alf P. Steinbach" <> wrote in
    > news:humcfr$7l7$-september.org:

    ....
    >> However, if a 'T const' in the declaration guaranteed a 'T const' in
    >> the definition, then the compiler could do this optimization, perhaps
    >> with some wording in the standard that you're in UB-land if you cast
    >> away the const.

    ....
    > And about adding new UB in the language - I would have thought there is
    > already too much of that.


    Surely it's already UB to cast away const on something which isn't
    already const?

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Jun 12, 2010
    #11
  12. Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    * Jorgen Grahn, on 12.06.2010 09:01:
    > On Tue, 2010-06-08, Paavo Helde wrote:
    >> "Alf P. Steinbach"<> wrote in
    >> news:humcfr$7l7$-september.org:

    > ...
    >>> However, if a 'T const' in the declaration guaranteed a 'T const' in
    >>> the definition, then the compiler could do this optimization, perhaps
    >>> with some wording in the standard that you're in UB-land if you cast
    >>> away the const.

    > ...
    >> And about adding new UB in the language - I would have thought there is
    >> already too much of that.

    >
    > Surely it's already UB to cast away const on something which isn't
    > already const?


    You probably meant to write the opposite, and even then it's not quite there
    (the UB is for casting away const on something that was originally const, and
    modifying).

    But anyway what you communicate is that I have advocated a language change.

    I have not.


    Cheers,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach, Jun 12, 2010
    #12
  13. Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    * Jorgen Grahn, on 12.06.2010 08:58:
    > On Tue, 2010-06-08, Alf P. Steinbach wrote:
    >> * Jorgen Grahn, on 08.06.2010 22:09:
    >>> On Tue, 2010-06-08, Alf P. Steinbach wrote:
    >>> ...
    >>>> However, only top level 'const' is disregarded for forming
    >>>> the function's type.
    >>>>
    >>>> E.g. 'int const' -> 'int', but not 'int const*' -> 'int*'.
    >>>
    >>> Which is a slightly convoluted way of saying "only the things that are
    >>> surely irrelevant to the interface are disregarded in the interface".

    >>
    >> That turns out to be a circular argument, because (see below) the 'const' is
    >> only irrelevant because of the current rules that it is disregarded...

    >
    > I was a bit too lazy to read your longer text carefully, but I suppose
    > I'm relying on the traditional meaning of call-by-value here, the one
    > you're taught in CS classes. *That* is what makes the const irrelevant
    > to the caller.


    Yes, the 'const' is irrelevant to the caller.

    However, in your first posting you wrote "only the things that are surely
    irrelevant to the interface are disregarded in the interface" as a way to
    remember the rule to disregard a top level 'const': "Easy to remember, and makes
    good sense".

    But as I then showed one can not deduce the rule from that: it is only with the
    current rules that the 'const' is irrelevant to the interface, not with other
    rules that could have been chosen. And so it's a circular argument that the rule
    to disregard the 'const' is a logical consequence of the 'const' being
    irrelevant, which it is because of the rule to disregard to it. And so on.


    > I don't see C++ moving away from call-by-value any time soon.


    That's probably correct. ;-)

    However, the implication that anyone has argued for such a change, is incorrect.


    Cheers & hth.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach, Jun 12, 2010
    #13
  14. Jorgen Grahn Guest

    Re: Acceptable to "const" a parameter in the definition but not inthe declaration?

    On Sat, 2010-06-12, Alf P. Steinbach wrote:
    > * Jorgen Grahn, on 12.06.2010 09:01:
    >> On Tue, 2010-06-08, Paavo Helde wrote:
    >>> "Alf P. Steinbach"<> wrote in
    >>> news:humcfr$7l7$-september.org:

    >> ...
    >>>> However, if a 'T const' in the declaration guaranteed a 'T const' in
    >>>> the definition, then the compiler could do this optimization, perhaps
    >>>> with some wording in the standard that you're in UB-land if you cast
    >>>> away the const.

    >> ...
    >>> And about adding new UB in the language - I would have thought there is
    >>> already too much of that.

    >>
    >> Surely it's already UB to cast away const on something which isn't
    >> already const?

    >
    > You probably meant to write the opposite,


    I meant to say:
    "it's UB to cast away const if the thing was const to begin with"

    > and even then it's not quite there
    > (the UB is for casting away const on something that was originally const, and
    > modifying).


    Ah, of course. That matches my usage: I sometimes may cast away const
    in order to call a function which takes a Foo* when a const Foo* would
    have been enough. Yes, I surely expect that to work.

    > But anyway what you communicate is that I have advocated a language change.
    >
    > I have not.


    I'm not talking about you or what you're advocating. I just thought it
    strange when Paavo thought this was a new UB. The "and modifying" part
    was what I was missing.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Jun 15, 2010
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    11
    Views:
    1,108
  2. Javier
    Replies:
    2
    Views:
    565
    James Kanze
    Sep 4, 2007
  3. Tomás Ó hÉilidhe

    Not quite standard... but socially acceptable

    Tomás Ó hÉilidhe, Apr 3, 2008, in forum: C Programming
    Replies:
    20
    Views:
    613
    Keith Thompson
    Apr 4, 2008
  4. 0m
    Replies:
    26
    Views:
    1,122
    Tim Rentsch
    Nov 10, 2008
  5. Amit Jain
    Replies:
    9
    Views:
    848
    Amit Jain
    Jul 21, 2009
Loading...

Share This Page