anonymous array of strings // ("taking address of temporary"- how long is temporary valid?)

Discussion in 'C++' started by anon.asdf@gmail.com, Feb 11, 2008.

  1. Guest

    Hello!

    1) ===============================
    When trying to define an array of std::string ...

    func( (std::string []) { std::string("ab"), std::string("cd"),
    std::string("ef") } , 3 );

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ....g++ tells me: "invalid use of non-lvalue array"
    Can the above be modified to work?

    void func(std::string arr[], int n)
    {
    while ((--n) >= 0) {
    std::cout << arr[n];
    }
    }


    2)================================

    When trying to work with an array of std::string-pointers ...

    func2( (std::string* []) { &std::string("ab"), &std::string("cd"),
    &std::string("ef") } , 3 );
    //
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // ~~ nextline

    .... g++ reports:
    "taking address of temporary" (reported 3 times)
    "invalid use of non-lvalue array".

    When are the 3 temporary addresses in danger of being "corrupted"? Is
    it during the execution of func2, or is it only after func2, i.e.
    at // ~~ nextline

    How can the error be fixed?

    void func2(std::string* arr[], int n)
    {

    // possible memory allocations etc...

    while ((--n) >= 0) {
    std::cout << *(arr[n]);
    }
    }



    Thanks for advice!
    -Albert
    , Feb 11, 2008
    #1
    1. Advertising

  2. Martin York Guest

    Re: anonymous array of strings // ("taking address of temporary" -how long is temporary valid?)

    On Feb 11, 7:06 am, wrote:
    > Hello!
    >
    > 1) ===============================
    > When trying to define an array of std::string ...
    >
    > func( (std::string []) { std::string("ab"), std::string("cd"),
    > std::string("ef") } , 3 );


    Perl programmer are we? :)

    Thats hard to read and I am not sure it would be valid syntax. It
    looks like a comma expression to me, I don't think you can use the
    array initializer like that (somebody with a copy of the standard will
    give you the exact problem). Also the fact that you are using a C
    style cast is an indication that something is not good with the code.

    A simple solution would be:

    std::string[] temp = {"ab","cd","ef"};
    func(temp,3);




    > func2( (std::string* []) { &std::string("ab"), &std::string("cd"),
    > &std::string("ef") } , 3 );
    > //
    > ... g++ reports:
    > "taking address of temporary" (reported 3 times)
    > "invalid use of non-lvalue array".



    Temporary objects are constant and only last as long as the statement.
    Thus taking there address is probably not a good idea that is why the
    compiler is generating a "WARNING". Also again I don't think you are
    actually creating an array. Using a cast like that forces the type to
    be something without checking. The compiler is not adding any code to
    do the conversion.


    > When are the 3 temporary addresses in danger of being "corrupted"? Is
    > it during the execution of func2, or is it only after func2, i.e.
    > at // ~~ nextline


    The temporaries are valid until the end of the statement they are
    created in (except in funny situations that don't arise here). So they
    will be valid until after func2() returns.
    Martin York, Feb 11, 2008
    #2
    1. Advertising

  3. Re: anonymous array of strings // ("taking address of temporary"- how long is temporary valid?)

    * Martin York -> :
    >
    >> func2( (std::string* []) { &std::string("ab"), &std::string("cd"),
    >> &std::string("ef") } , 3 );
    >> //
    >> ... g++ reports:
    >> "taking address of temporary" (reported 3 times)
    >> "invalid use of non-lvalue array".

    >
    >
    > Temporary objects are constant


    Nope.

    Temporaries behave like being constant wrt. to binding to references.

    But they're not constant unless they have const type, and in particular,
    you can call non-const non-static member functions on a temporary of
    class type (unless the type is const), which includes assignment to a
    temporary of class type, because operator= is then a member function...

    struct S {};

    void foo( S& ) {}

    int main()
    {
    S() = S(); // OK.
    // foo( S() ); // Ungood.
    }

    Cheers, & hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Feb 11, 2008
    #3
  4. Guest

    Re: anonymous array of strings // ("taking address of temporary" -how long is temporary valid?)

    On 11 Feb., 16:06, anon.asdf wrote:
    > Hello!
    >
    > 1) ===============================
    > When trying to define an array of std::string ...
    >
    > func( (std::string []) { std::string("ab"), std::string("cd"),
    > std::string("ef") } , 3 );
    >
    > void func(std::string arr[], int n)
    > {
    > while ((--n) >= 0) {
    > std::cout << arr[n];
    > }
    >
    > }


    Interestingly, the following works fine:

    //===================================
    #include <iostream>

    void func3(char* arr[], int n);

    int main(void)
    {
    func3((char* []){"ab", "cd", "ef"}, 3);
    return 0;
    }

    void func3(char* arr[], int n)
    {
    while ((--n) >= 0) {
    std::cout << arr[n];
    }
    std::cout << std::endl;
    }
    //===================================

    Can it be similarly adapted for std::string, without naming an array
    variable?

    -Albert
    , Feb 12, 2008
    #4
  5. Re: anonymous array of strings // ("taking address of temporary"- how long is temporary valid?)

    * :
    > On 11 Feb., 16:06, anon.asdf wrote:
    >> Hello!
    >>
    >> 1) ===============================
    >> When trying to define an array of std::string ...
    >>
    >> func( (std::string []) { std::string("ab"), std::string("cd"),
    >> std::string("ef") } , 3 );
    >>
    >> void func(std::string arr[], int n)
    >> {
    >> while ((--n) >= 0) {
    >> std::cout << arr[n];
    >> }
    >>
    >> }

    >
    > Interestingly, the following works fine:
    >
    > //===================================
    > #include <iostream>
    >
    > void func3(char* arr[], int n);
    >
    > int main(void)
    > {
    > func3((char* []){"ab", "cd", "ef"}, 3);
    > return 0;
    > }
    >
    > void func3(char* arr[], int n)
    > {
    > while ((--n) >= 0) {
    > std::cout << arr[n];
    > }
    > std::cout << std::endl;
    > }
    > //===================================


    <quote>
    V:\> gnuc vc_project.cpp
    vc_project.cpp: In function `int main()':
    vc_project.cpp:7: error: ISO C++ forbids compound-literals

    V:\> msvc vc_project.cpp
    vc_project.cpp
    vc_project.cpp(7) : error C2143: syntax error : missing ')' before '{'
    vc_project.cpp(7) : error C2059: syntax error : ')'
    vc_project.cpp(7) : error C2143: syntax error : missing ';' before '{'
    vc_project.cpp(7) : error C2143: syntax error : missing ';' before '}'
    vc_project.cpp(7) : error C2143: syntax error : missing ';' before ','
    vc_project.cpp(7) : error C2059: syntax error : ')'

    V:\>_
    </quote>


    > Can it be similarly adapted for std::string, without naming an array
    > variable?


    No.

    It seems the compiler+options you're using allows the above as an extension.

    It might be that it's syntax that has been introduced in C99, but it's
    not C++.


    Cheers, & hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Feb 12, 2008
    #5
  6. Re: anonymous array of strings // ("taking address of temporary" -how long is temporary valid?)

    On 11 Feb, 21:06, "Alf P. Steinbach" <> wrote:
    > Temporaries behave like being constant wrt. to binding to references.
    >
    > But they're not constant unless they have const type, and in particular,
    > you can call non-const non-static member functions on a temporary of
    > class type (unless the type is const), which includes assignment to a
    > temporary of class type, because operator= is then a member function...
    >


    What is the reason for this behaviour?

    It seems to me that it breaks the distinction between R-value and L-
    value. The following two snippets:

    X a, b, c;
    a + b = c;

    X f(); // extern function
    void g()
    {
    X x;
    f() += x;
    }

    both cause a compile error when X = int, but they become valid (at
    least, with all the compilers and libraries that I could test) if I
    use X = std::complex<int> or X = std::string. And they both look like
    logical errors by the programmer.

    Furthermore, as pointed out by some previous threads in this
    newsgroup, this behaviour introduces a difference between an operator
    declared as a class method and the same operator declared as a global
    function; this difference may also lead to bugs that are hard to track
    and hard to explain to novice programmers.

    What do we gain from this feature?

    Dario
    Dario Saccavino, Feb 12, 2008
    #6
  7. Re: anonymous array of strings // ("taking address of temporary"- how long is temporary valid?)

    * Dario Saccavino:
    > On 11 Feb, 21:06, "Alf P. Steinbach" <> wrote:
    >> Temporaries behave like being constant wrt. to binding to references.
    >>
    >> But they're not constant unless they have const type, and in particular,
    >> you can call non-const non-static member functions on a temporary of
    >> class type (unless the type is const), which includes assignment to a
    >> temporary of class type, because operator= is then a member function...
    >>

    >
    > What is the reason for this behaviour?
    >
    > It seems to me that it breaks the distinction between R-value and L-
    > value. The following two snippets:
    >
    > X a, b, c;
    > a + b = c;
    >
    > X f(); // extern function
    > void g()
    > {
    > X x;
    > f() += x;
    > }
    >
    > both cause a compile error when X = int, but they become valid (at
    > least, with all the compilers and libraries that I could test) if I
    > use X = std::complex<int> or X = std::string. And they both look like
    > logical errors by the programmer.


    Heh heh. :) It's much worse. Consider

    struct S { int v; };

    S foo() { return S(); }

    int main()
    {
    foo() = S(); // OK, can change the whole shebang.
    foo().v = 0; // Nyet! Can not change part!
    }

    As it happens both g++ 3.4.4 and msvc 7.1 compile this fine (or rather,
    erronously), but Comeau Online 4.3.9 reports for the last assignment
    that "expression must be a modifiable lvalue".


    > Furthermore, as pointed out by some previous threads in this
    > newsgroup, this behaviour introduces a difference between an operator
    > declared as a class method and the same operator declared as a global
    > function;


    Good observation. May relate to why operator= can only be defined as a
    member function. Bjarne stated somewhere that it was to (my words) keep
    some degree of sanity, something you could rely on, and I had difficulty
    understanding what that meant, but possibly it could refer to the
    discrimination between rvalues and lvalues that a freestanding operator=
    would give. Although I still do not quite understand it. Possibly the
    rvalue/lvalue distinction doesn't really make sense in C++.

    This discussion could possibly benefit from being brought to comp.std.c++.

    Except -- that group's temporarily down.


    > this difference may also lead to bugs that are hard to track
    > and hard to explain to novice programmers.
    >
    > What do we gain from this feature?


    One example that I remember being mentioned is, for a multi-dimensional
    logical array, the ability to define an operator[] that returns a proxy
    object that can be assigned to (the first level proxy object would then
    itself also provide an operator[], the purpose being to not expose the
    logical array's internal memory layout or general implementation).

    However, in most real-world cases the proxy object would not need to be
    modified by the assignment, so you could define

    struct Proxy
    {
    Proxy const& operator=( SomeElementType const& ) const;
    };

    So I think perhaps a better example is the stringizer (or more generally
    the idea of chaining calls, used e.g. in named arguments idiom),

    struct Str
    {
    std::eek:stringstream stream;

    template< typename T >
    Str& operator<<( T const& v ) { stream << v; return *this; }

    operator std::string() const { return stream.str(); }
    };

    void foo( std::string const& ) {}

    int main()
    {
    foo( Str() << "Line " << 42 << "." );
    }


    Cheers,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Feb 12, 2008
    #7
  8. James Kanze Guest

    Re: anonymous array of strings // ("taking address of temporary" -how long is temporary valid?)

    On Feb 12, 11:17 am, "Alf P. Steinbach" <> wrote:
    > * Dario Saccavino:
    > > On 11 Feb, 21:06, "Alf P. Steinbach" <> wrote:
    > >> Temporaries behave like being constant wrt. to binding to
    > >> references.


    > >> But they're not constant unless they have const type, and
    > >> in particular, you can call non-const non-static member
    > >> functions on a temporary of class type (unless the type is
    > >> const), which includes assignment to a temporary of class
    > >> type, because operator= is then a member function...


    > > What is the reason for this behaviour?


    I'd consider it mainly a side effect of a lot of other
    decisions. Each one justified in isolation, but the final
    results can be rather confusing.

    > > It seems to me that it breaks the distinction between
    > > R-value and L- value. The following two snippets:


    > > X a, b, c;
    > > a + b = c;


    > > X f(); // extern function
    > > void g()
    > > {
    > > X x;
    > > f() += x;
    > > }


    > > both cause a compile error when X = int, but they become
    > > valid (at least, with all the compilers and libraries that I
    > > could test) if I use X = std::complex<int> or X =
    > > std::string. And they both look like logical errors by the
    > > programmer.


    > Heh heh. :) It's much worse. Consider


    > struct S { int v; };


    > S foo() { return S(); }


    > int main()
    > {
    > foo() = S(); // OK, can change the whole shebang.
    > foo().v = 0; // Nyet! Can not change part!
    > }


    > As it happens both g++ 3.4.4 and msvc 7.1 compile this fine
    > (or rather, erronously), but Comeau Online 4.3.9 reports for
    > the last assignment that "expression must be a modifiable
    > lvalue".


    Yep. The real problem here (or at least one way of viewing it)
    is that in the first case, you're dealing with a member function
    (S::eek:perator=()---the fact that the compiler writes it, and not
    you, doesn't change things here), and not an assignment
    operator, so the rules concerning calling a member function
    apply. In the second, of course, it's the built-in operator =
    which is being used.

    The built-in operator = requires an lvalue. A member function
    doesn't.

    > > Furthermore, as pointed out by some previous threads in this
    > > newsgroup, this behaviour introduces a difference between an
    > > operator declared as a class method and the same operator
    > > declared as a global function;


    > Good observation. May relate to why operator= can only be
    > defined as a member function. Bjarne stated somewhere that it
    > was to (my words) keep some degree of sanity, something you
    > could rely on, and I had difficulty understanding what that
    > meant, but possibly it could refer to the discrimination
    > between rvalues and lvalues that a freestanding operator=
    > would give. Although I still do not quite understand it.
    > Possibly the rvalue/lvalue distinction doesn't really make
    > sense in C++.


    I suspect that his statement referred more to what might happen
    if the declaration of a non member operator= was visible in some
    cases, and not in others. Sometimes getting the compiler
    generated default when you've declared one explicitly would also
    be very, very confusing.

    The problem remains that the concept of lvalue/rvalue, as
    inherited from C, doesn't work very well with objects of class
    type. There are a couple of patterns where being able to call
    member functions on a temporary object is essential. The
    standard wanted to support that. Binding a temporary to a
    non-const reference had proven to be seriously error prone. The
    standard wanted to forbid it. (Note that these two rules
    together mean that a user defined operator++ can be used on a
    temporary, if it is a member function, but not if it is a free
    function.) And the standard also tries to maintain the C
    distinction between lvalues and rvalues where it can. The
    results are confusing to say the least.

    > This discussion could possibly benefit from being brought to
    > comp.std.c++.


    > Except -- that group's temporarily down.


    Only temporarily, I hope. (It's been down for more than a month
    now.)

    > > this difference may also lead to bugs that are hard to track
    > > and hard to explain to novice programmers.


    > > What do we gain from this feature?


    > One example that I remember being mentioned is, for a
    > multi-dimensional logical array, the ability to define an
    > operator[] that returns a proxy object that can be assigned to
    > (the first level proxy object would then itself also provide
    > an operator[], the purpose being to not expose the logical
    > array's internal memory layout or general implementation).


    > However, in most real-world cases the proxy object would not
    > need to be modified by the assignment, so you could define


    > struct Proxy
    > {
    > Proxy const& operator=( SomeElementType const& ) const;
    > };


    That's what Scott Meyers suggests. It has the advantage that it
    very much signals the object as a Proxy---the fact that
    operator= is const should definitely signal something.

    > So I think perhaps a better example is the stringizer (or more generally
    > the idea of chaining calls, used e.g. in named arguments idiom),


    > struct Str
    > {
    > std::eek:stringstream stream;


    > template< typename T >
    > Str& operator<<( T const& v ) { stream << v; return *this; }


    > operator std::string() const { return stream.str(); }
    > };


    > void foo( std::string const& ) {}


    > int main()
    > {
    > foo( Str() << "Line " << 42 << "." );
    > }


    I think that's more or less the real argument. The example I
    remember was something like:

    new Window( WindowParameters().background( Color::red ) ) ;

    A window can typically have something like a hundred different
    parameters, most of which will use the default value most of the
    time. So you wrap them in a WindowParameters class, whose
    constructor sets them all to the default value, and then you
    call explicit functions (which return a WindowParameters&) to
    change the ones you want changed.

    There are possible alternative rules, but they all fall down
    somewhere as well.

    --
    James Kanze (GABI Software) email:
    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
    James Kanze, Feb 12, 2008
    #8
    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:
    0
    Views:
    1,118
  2. Replies:
    3
    Views:
    725
  3. Andy Gibbs
    Replies:
    5
    Views:
    4,036
    Andy Gibbs
    Nov 19, 2008
  4. V.Subramanian, India

    taking address of temporary object

    V.Subramanian, India, Feb 10, 2012, in forum: C++
    Replies:
    2
    Views:
    1,017
    Alf P. Steinbach
    Feb 10, 2012
  5. Replies:
    1
    Views:
    218
Loading...

Share This Page