Thread: error: cannot convert 'std::string' to 'std::string*' in assignment??

  1. #16
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Well, if Programmer_P ever uses Sebastiani's idea, then comes round asking why there was a mismatch in the number of constructor and destructor invocations, then Sebastiani better be at hand to give a good answer, or we get to roast him over a slow burning fire

    Quote Originally Posted by Sebastiani
    Sorry, but that's incorrect - the code just invokes the constructor on an existing object, so the reference member 'data' does indeed get reassigned.
    No, it does not. We're dealing with a new object. What happens is that the constructor is invoked to create a new object, which is then placed in memory in the same location as an existing object.
    Last edited by laserlight; 06-02-2010 at 01:47 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  2. #17
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by iMalc View Post
    If you start posting non-kosher code examples like that, I think you're obliged to pay attention to the distinction between "reassigning a reference" and "unscroupulously causing the underlying memory occupied by a reference to change".

    No code example like that is going to negate the fact that references cant be reassigned.
    Hey - I was just pointing out that it is possible! And the distinction you make is understandable, if pedantic - my example was 100% portable C++, with clearly defined behaviour, and the reference in question is *effectively* reassigned. It ain't pretty, and it may very well raise eyebrows in a code review, but it nonetheless works just fine.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #18
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Sebastiani
    Hey - I was just pointing out that it is possible! And the distinction you make is understandable, if pedantic - my example was 100% portable C++, with clearly defined behaviour, and the reference in question is *effectively* reassigned.
    I am not sure about that:
    Quote Originally Posted by C++03 Section 8.5.3 Paragraph 2
    A reference cannot be changed to refer to another object after initialization.
    Quote Originally Posted by Sebastiani
    It ain't pretty, and it may very well raise eyebrows in a code review, but it nonetheless works just fine.
    Even if we accept that it is "100% portable C++, with clearly defined behaviour", the program must be incorrect: it cannot possibly be correct that there are two constructor invocations but only one destructor invocation. I would completely slam it in a code review, on the grounds of correctness.

    EDIT:
    I suppose you could correct the code by explicitly invoking the destructor on r before placement new, but then you would need very calm colleagues for them to merely "raise eyebrows in a code review".
    Last edited by laserlight; 06-02-2010 at 02:09 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #19
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Well, if Programmer_P ever uses Sebastiani's idea, then comes round asking why there was a mismatch in the number of constructor and destructor invocations, then Sebastiani better be at hand to give a good answer, or we get to roast him over a slow burning fire
    Fair enough, but let's face it - given his track record, the chances that he actually follows any advice here is pretty slim.

    No, it does not. We're dealing with a new object. What happens is that the constructor is invoked to create a new object, which is then placed in memory in the same location as an existing object.
    Actually, the constructor is invoked on the existing object, just as if it had been declared at the point of the "placement new" call.

    Code:
    template < typename Type >
    struct reference
    {
        reference( Type& data )
        : data( data )
        {    
            cout << "Construct: " << static_cast< void* >( this ) << endl;
        }
        
        Type& 
            data;
    };
    
    int main( void )
    {
        int 
            i = 1024,
            j = i + 1;
        reference< int >
            r( i );
        cout << r.data << endl;
        new( &r ) reference< int >( j );
        cout << r.data << endl;
    }
    Output:

    Construct: 0x28ff10
    1024
    Construct: 0x28ff10
    1025
    Two constructor calls, one address.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  5. #20
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Sebastiani
    Actually, the constructor is invoked on the existing object, just as if it had been declared at the point of the "placement new" call.
    That does not make sense. You cannot construct an object twice.

    Quote Originally Posted by Sebastiani
    Two constructor calls, one address.
    That confirms the statement that the new object is placed in the same location as the existing object. In fact, this should be well known to you, since it is an intended effect of placement new.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #21
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by Sebastiani View Post
    Fair enough, but let's face it - given his track record, the chances that he actually follows any advice here is pretty slim.
    And yet I'm playing with your code right now...

  7. #22
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    I am not sure about that: A reference cannot be changed to refer to another object after initialization.
    As a syntactic feature, yes, insomuch as you can't reassign a "raw" reference. But the rules governing the behaviour of "placement new" guarantee that it can be done "in practice", on structures that contain references.

    Even if we accept that it is "100% portable C++, with clearly defined behaviour", the program must be incorrect: it cannot possibly be correct that there are two constructor invocations but only one destructor invocation. I would completely slam it in a code review, on the grounds of correctness.
    Well, in this case the destructor invocation is superfulous, but yes, matching the calls is, of course, the correct way to do it.

    I should probably reiterate at this point that I am not advocating this sort of practice - I just have this odd fascination with "bending the rules" of the language. It's a hobby, I guess.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #23
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Sebastiani
    BAs a syntactic feature, yes, insomuch as you can't reassign a "raw" reference. But the rules governing the behaviour of "placement new" guarantee that it can be done "in practice", on structures that contain references.
    Then we simply disagree. In my opinion, you are not doing such a thing in practice. You are merely deceiving yourself by not recognising that the reference member belongs to another object that is placed into the same location as the existing object (EDIT: or perhaps, into the location of an explicitly destroyed object).
    Last edited by laserlight; 06-02-2010 at 02:40 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #24
    Registered User
    Join Date
    Mar 2010
    Posts
    109
    I enjoyed the debate. I would still say you cannot reassign a reference, but I think it's more an argument of semantics at this point. It seems that, effectively, it is possible.

  10. #25
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by laserlight View Post
    Then we simply disagree. In my opinion, you are not doing such a thing in practice. You are merely deceiving yourself by not recognising that the reference member belongs to another object that is placed into the same location as the existing object.
    Yes, I would say laserlight is right.
    You're not actually reassigning the reference to the first object to the second object, per se. You're only getting a new reference (though using the same name) to a new object at the same memory address as that held by the former object.

    The difference though is after reassigning a pointer, you're pointing at a different memory address altogether, while with the reference using your method, you're using the same memory address, only a different object.
    Last edited by Programmer_P; 06-02-2010 at 02:51 PM.

  11. #26
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    That does not make sense. You cannot construct an object twice.
    Sure you can. A constructor is nothing more than a function call, after all.

    That confirms the statement that the new object is placed in the same location as the existing object. In fact, this should be well known to you, since it is an intended effect of placement new.
    There is no "new object". The compiler generates the same code as it did when the object was declared, eg: a pointer to the *original* object is passed to the class constructor. Consider:

    Code:
    int main( void )
    {
        int 
            i = 1024,
            j = i + 1;
        unsigned char
            b[ sizeof( reference< int > ) ];
        reference< int >&
            r( *( reference< int >* )b );
        new( &r ) reference< int >( i );
        cout << r.data << endl;
        new( &r ) reference< int >( j );
        cout << r.data << endl;
    }
    Output:

    Construct: 0x28ff10
    1024
    Construct: 0x28ff10
    1025
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  12. #27
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Sebastiani
    Sure you can. A constructor is nothing more than a function call, after all.
    You might want to read GotW #66 to learn about object lifetimes.

    Quote Originally Posted by Sebastiani
    There is no "new object". The compiler generates the same code as it did when the object was declared, eg: a pointer to the *original* object is passed to the class constructor.
    It sounds like you are thinking from the perspective of C rather than C++, but C does not have constructors. A constructor is used to create a new object, by definition. Hence, it is fundamentally impossible to create the same object twice, even though a constructor call is otherwise just a function call.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #28
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    You might want to read GotW #66 to learn about object lifetimes.
    [...]
    It sounds like you are thinking from the perspective of C rather than C++, but C does not have constructors. A constructor is used to create a new object, by definition. Hence, it is fundamentally impossible to create the same object twice, even though a constructor call is otherwise just a function call.
    ...and for that, I award you the Pedantic Argument of the Day.

    Okay, in terms of "object lifetimes", this is indeed true. Nonetheless, the code generated by the compiler is *precisely* the same whether it is dealing with a "standard" constructor invocation or a "manual" one (eg: "placement new"). Moreover, to "create" an object, the compiler simply (1) sets aside enough memory for the object, and then (2) passes a pointer to the object to the class constructor. When you invoke "placement new" on the object, you are just repeating step #2. So, more accurately, "A constructor is used to initialize a (typically, but not necessarily) new object".
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  14. #29
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Sebastiani
    I award you the Pedantic Argument of the Day.
    Thank you, thank you. I shall forgo the acceptance speech

    Quote Originally Posted by Sebastiani
    Moreover, to "create" an object, the compiler simply (1) sets aside enough memory for the object, and then (2) passes a pointer to the object to the class constructor. When you invoke "placement new" on the object, you are just repeating step #2.
    To justify my pedantic argument award: the pointer at that point points to the memory set aside, since the object does not yet exist, and in typical usage of placement new, step #2 is done once rather than repeated (unless the memory is merely reused incidentally).

    Quote Originally Posted by Sebastiani
    So, more accurately, "A constructor is used to initialize a (typically, but not necessarily) new object".
    That implies that a constructor can initialize an existing object. Yes, not assignment to an existing object, but initialisation. Maybe it makes sense to you, but it definitely makes no sense to me. It is like turning the semantics upside down.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #30
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by laserlight View Post
    Thank you, thank you. I shall forgo the acceptance speech


    To justify my pedantic argument award: the pointer at that point points to the memory set aside, since the object does not yet exist, and in typical usage of placement new, step #2 is done once rather than repeated (unless the memory is merely reused incidentally).


    That implies that a constructor can initialize an existing object. Yes, not assignment to an existing object, but initialisation. Maybe it makes sense to you, but it definitely makes no sense to me. It is like turning the semantics upside down.
    Okay, fair enough. And for the record, your arguments, pedantic or otherwise, are usually spot on, and so I encouraged you to display your award prominently - right next to all of those "Best Damn Advice of the Day" awards you've racked up.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Menu
    By Krush in forum C Programming
    Replies: 17
    Last Post: 09-01-2009, 02:34 AM
  2. Convert uint16_t to std::string?
    By magicalo in forum C++ Programming
    Replies: 3
    Last Post: 07-18-2008, 01:34 AM
  3. Replies: 8
    Last Post: 03-10-2008, 11:57 AM
  4. What is the easies way to convert int to std::string?
    By meili100 in forum C++ Programming
    Replies: 6
    Last Post: 12-04-2007, 02:15 AM
  5. Replies: 1
    Last Post: 10-27-2006, 01:21 PM