c_str from anonymous std::string

A

Andrew Tomazos

class X
{
operator std::string(); // stringify X instance
};

void f(const char*);

X x = ...
f(string(x).c_str());

According to the C++11 standard, will the destructor of std::string be
called before or after the call to f, or is it undefined?

Thanks,
Andrew.
 
S

SG

class X
{
    operator std::string(); // stringify X instance
};

void f(const char*);

X x = ...
f(string(x).c_str());

According to the C++11 standard, will the destructor of std::string be
called before or after the call to f, or is it undefined?

After. The code is fine.

Cheers!
SG
 
G

Goran

class X
{
    operator std::string(); // stringify X instance

};

void f(const char*);

X x = ...
f(string(x).c_str());

According to the C++11 standard, will the destructor of std::string be
called before or after the call to f, or is it undefined?

My understanding is that such temporaries is destroyed when statement
is finished, which, here, is after the semicolon.

Goran.
 
M

MikeWhy

Goran said:
My understanding is that such temporaries is destroyed when statement
is finished, which, here, is after the semicolon.

It should be further noted that "string(x)" here is an explicit C-style
typecast, syntactically identical to "((std::string)x)", followed by copy
construction of std::string, creating not just one, but *two* temporary
std::string. What a nasty bit of business. This isn't real code, is it? Just
some contrived nastiness to astonish and dismay job applicants?
 
T

Tobias Müller

MikeWhy said:
It should be further noted that "string(x)" here is an explicit C-style
typecast, syntactically identical to "((std::string)x)", followed by copy
construction of std::string, creating not just one, but *two* temporary
std::string. What a nasty bit of business. This isn't real code, is it?
Just some contrived nastiness to astonish and dismay job applicants?

Really? Why is operator std::string /followed/ by a copy constuctor? There
is a copy /on returning/ a std::string from the operator function but this
is an inherent "problem" of returning by value and not the fault of the
rest of the code ("problem" in quotes, because this is optimized away by
most compilers).

Or am I misunderstanding something obvious?

Tobi
 
J

Juha Nieminen

MikeWhy said:
It should be further noted that "string(x)" here is an explicit C-style
typecast, syntactically identical to "((std::string)x)"

It looks like a regular object instantiation by calling its constructor
to me. (The latter is also interpreted like that.)

How else would you construct a temporary object?
 
I

Ian Collins

It should be further noted that "string(x)" here is an explicit C-style
typecast, syntactically identical to "((std::string)x)", followed by copy
construction of std::string, creating not just one, but *two* temporary
std::string.

In addition to the other corrections, there really isn't such a thing as
an "explicit C-style typecast". There is a C style cast (witch is
always explicit) and there's a type conversion (which is isn't).
 
A

Andrew Tomazos

It should be further noted that "string(x)" here is an explicit C-style
typecast, syntactically identical to "((std::string)x)", followed by copy
construction of std::string, creating not just one, but *two* temporary
std::string.

$ cat < test.cpp

#include <iostream>

using namespace std;

class A
{
public:
A() { cout << "d"; }
A(const A& a) : x(a.x) { cout << "c"; }

int getx() const { return x; }
int x;
};

class B
{
public:
B(int i) : x(i) {}
operator A() { A a; a.x = x; return a; }

int x;
};

void f(int x) { cout << x << endl; }

int main(int argc, char** argv)
{
B b(argc);

f(A(b).getx());
}

$ g++ test.cpp
$ ./a.out
d1

I only count one d. :)

Due to the return value optimization...
What a nasty bit of business. This isn't real code, is it? Just
some contrived nastiness to astonish and dismay job applicants?

Imagine how much less embarrassed you would be if you stated it this
way:

"I think that two temporaries will be created, won't they?"

and left it at that. ;)

Enjoy,
Andrew.
 
M

MikeWhy

Andrew said:
$ cat < test.cpp

#include <iostream>

using namespace std;

class A
{
public:
A() { cout << "d"; }
A(const A& a) : x(a.x) { cout << "c"; }

int getx() const { return x; }
int x;
};

class B
{
public:
B(int i) : x(i) {}
operator A() { A a; a.x = x; return a; }

int x;
};

void f(int x) { cout << x << endl; }

int main(int argc, char** argv)
{
B b(argc);

f(A(b).getx());
}

$ g++ test.cpp
$ ./a.out
d1

I only count one d. :)

Due to the return value optimization...


Imagine how much less embarrassed you would be if you stated it this
way:

"I think that two temporaries will be created, won't they?"

and left it at that. ;)

Enjoy,
Andrew.

Cause for my embarrassment is wholly imaginary.

The following produced:

[[
Boo::eek:perator ZooString()const
ZooString<0013FF48>::ZooString(const char *) {Boo}
ZooString<0013FF2C>::ZooString(const ZooString &) {Boo}
Boo
]]

Note the copy construction.



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

//================================
//================================
class ZooString
{
public:
ZooString(const char * s = "")
: str(s)
{ PrintTo(std::cout, "::ZooString(const char *)") << '\n';
}

ZooString(const ZooString & r)
: str(r.str)
{ PrintTo(std::cout, "::ZooString(const ZooString &)") << '\n';
}

const char * c_str() const
{
return str.c_str();
}

std::eek:stream & PrintTo(std::eek:stream & os, const char * msg) const
{
os << "ZooString<" << (void*)this << '>' << msg
<< " {" << str << '}';
return os;
}
private:
std::string str;
};
//================================
//================================
class Boo
{
public:
Boo(){}
Boo(const Boo &);
operator ZooString() const
{ std::cout << "Boo::eek:perator ZooString()const\n";
return "Boo";
}
};
//================================
//================================
int main(int, char**)
{
Boo hoo;
std::cout << ZooString(hoo).c_str() << '\n';

return 0;
}
 
A

Andrew Tomazos

$ cat < test.cpp
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "d"; }
A(const A& a) : x(a.x) { cout << "c"; }
int getx() const { return x; }
int x;
};
class B
{
public:
B(int i) : x(i) {}
operator A() { A a; a.x = x; return a; }
int x;
};
void f(int x) { cout << x << endl; }
int main(int argc, char** argv)
{
B b(argc);

$ g++ test.cpp
$ ./a.out
d1
I only count one d. :)
Imagine how much less embarrassed you would be if you stated it this
way:
    "I think that two temporaries will be created, won't they?"
and left it at that. ;)
Enjoy,
    Andrew.

Cause for my embarrassment is wholly imaginary.

The following produced:

[[
Boo::eek:perator ZooString()const
ZooString<0013FF48>::ZooString(const char *) {Boo}
ZooString<0013FF2C>::ZooString(const ZooString &) {Boo}
Boo
]]

Note the copy construction.

So get a real compiler...

$ g++ YourExample.cpp
$ ./a.out
Boo::eek:perator ZooString()const
ZooString<0x7fff335e93e0>::ZooString(const char *) {Boo}
Boo

$ g++ --version
g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

Regards,
Andrew.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top