views:

254

answers:

4
+1  Q: 

Is this valid C++?

struct SomeStruct
{
  int a; 
  int b;
};

SomeStruct someFn( int init )
{
  SomeStruct ret = { init, init };
  //...
  return ret;
}

void someFn2( SomeStruct* pStruct )
{
  // ..
}

int main( )
{
  someFn2( &someFn(32) );
  return 0;
}
+18  A: 

No, it's not valid.

From 5.2.2/10 [expr.call] "A function call is an lvalue if and only if the result type is a reference.

From 5.3.1/2 [expr.unary.op] "The operand shall be an lvalue or a qualified-id".

someFn(32) is, therefore, not an lvalue as SomeStruct is not a reference and you are using it as the operand to & which requires an lvalue.

Charles Bailey
+6  A: 
$ g++ -Wall -o stuct struct.cc 
struct.cc: In function ‘int main()’:
struct.cc:21: warning: taking address of temporary

You should probably be doing:

int main( )
{
  SomeStruct s = someFn(32);
  someFn2(&s);
  return 0;
}
Brian Campbell
+4  A: 

No it's not.

You can only use & on lvalues. SomeFn(32) is not a lvalue.

Your main should be like this :

int main( )
{
  SomeStruct s;
  s = someFn(32);
  someFn2(&s);
  return 0;
}
246tNt
+3  A: 

The usual idiom is to pass a const reference rather than a pointer if your function can accept temporaries.

#include<iostream>

struct SomeStruct {
    int a;
    int b;

    ~SomeStruct() {
        std::cout << "SomeStruct destroyed" << std::endl;
    }
};

SomeStruct someFn ( int init )
{
    SomeStruct ret = { init, init };
    return ret;
}

void someFn2 ( SomeStruct* pStruct )
{
    std::cout << "someFn2 called" << std::endl;
}

void someFn2 ( const SomeStruct& someStruct )
{
    std::cout << "someFn2 called" << std::endl;
}

int main( )
{
    someFn2 ( &someFn ( 32 ) ); // warning - taking address of temporary
    someFn2 ( someFn ( 32 ) ); // no warning - safe in non-broken compilers
    return 0;
}

outputs

someFn2 called
SomeStruct destroyed
someFn2 called
SomeStruct destroyed

IIRC, the set of 'non-broken' compilers does not include Visual C++ 2003 or earlier.

An example of this idiom in the stl would be:

string a = "red";
string b = " apple";
string c = a + b;

where the std::string(const std::string&) constructor is called for c with the temporary std::string returned from the call to std::string::operator+ .

Pete Kirkham