temporary function parameters

S

stf

The question is whether function calls that use temporary objects,
like this:

testMethod(BufferWrapper("test string").getContents());

are legal. Is BufferWrapper destructor *guaranteed* to be called
*after* testMethod has returned?

Here the full code:

#include <iostream>
#include <cstring>

using namespace std;

class BufferWrapper {
public:
BufferWrapper(const char *s);
virtual ~BufferWrapper();

virtual const char* getContents() const;

private:
char *pContents;
};

BufferWrapper::BufferWrapper(const char *s) {
cerr << "BufferWrapper::BufferWrapper : " << s << endl;
int len = strlen(s);
pContents = new char[1 + len];
strncpy(pContents, s, len);
pContents[len] = 0;
}

BufferWrapper::~BufferWrapper() {
cerr << "BufferWrapper::~BufferWrapper: " << pContents << endl;

if (pContents) {
delete [] pContents;
pContents = NULL;
}
}

const char* BufferWrapper::getContents() const {
return pContents;
}

void testMethod(const char *s) {
cerr << "testMethod: " << s << endl;
}

int main() {
testMethod(BufferWrapper("test string").getContents());
return 0;
}

I also noticed that if temporary object creation is wrapped inside
inline function, then it gets destroyed before that function returns:

inline const char* f() {
return BufferWrapper("test string").getContents()
}

testMethod(f()); // On testMethod call BufferWrapper does not exist!

So, if BufferWrapper class has a very_long_name and is used very
frequently in the pattern like this (for temporary method
parameters) what can I do to make the code shorter? Use a macro??

Thank you!

STF
 
V

Victor Bazarov

The question is whether function calls that use temporary objects,
like this:

testMethod(BufferWrapper("test string").getContents());

are legal. Is BufferWrapper destructor *guaranteed* to be called
*after* testMethod has returned?
Yes.


Here the full code:

#include<iostream>
#include<cstring>

using namespace std;

class BufferWrapper {
public:
BufferWrapper(const char *s);
virtual ~BufferWrapper();

virtual const char* getContents() const;

private:
char *pContents;
};

BufferWrapper::BufferWrapper(const char *s) {
cerr<< "BufferWrapper::BufferWrapper : "<< s<< endl;
int len = strlen(s);
pContents = new char[1 + len];
strncpy(pContents, s, len);
pContents[len] = 0;
}

BufferWrapper::~BufferWrapper() {
cerr<< "BufferWrapper::~BufferWrapper: "<< pContents<< endl;

if (pContents) {
delete [] pContents;
pContents = NULL;
}
}

const char* BufferWrapper::getContents() const {
return pContents;
}

void testMethod(const char *s) {
cerr<< "testMethod: "<< s<< endl;
}

int main() {
testMethod(BufferWrapper("test string").getContents());
return 0;
}

I also noticed that if temporary object creation is wrapped inside
inline function, then it gets destroyed before that function returns:

inline const char* f() {
return BufferWrapper("test string").getContents()
}

testMethod(f()); // On testMethod call BufferWrapper does not exist!

Not sure what your comment here means.
So, if BufferWrapper class has a very_long_name and is used very
frequently in the pattern like this (for temporary method
parameters) what can I do to make the code shorter? Use a macro??

Sure. Or a typedef:

class SomeVeryLongAndAwkwardToTypeClassNameHere {
...
};

typedef SomeVeryLongAndAwkwardToTypeClassNameHere Name;

... Name(... ; // instead of the long name

V
 
Ö

Öö Tiib

The question is whether function calls that use temporary objects,
like this:

testMethod(BufferWrapper("test string").getContents());

are legal. Is BufferWrapper destructor *guaranteed* to be called
*after* testMethod has returned?

Yes.

I also noticed that if temporary object creation is wrapped inside
inline function, then it gets destroyed before that function returns:

inline const char* f() {
return BufferWrapper("test string").getContents()

}

Yes. It is undefined behavior if you return pointers to parts of local
objects.
So, if BufferWrapper class has a very_long_name and is used very
frequently in the pattern like this (for temporary method
parameters) what can I do to make the code shorter? Use a macro??

No. Use std::string and dump your BufferWrapper.

#include <iostream>
#include <string>

using namespace std;

typedef std::string BufferWrapper;

void testMethod(const BufferWrapper& s) {
cerr << "testMethod: " << s.c_str() << endl;
}

int main() {
testMethod("test string"); // implicit constructor
return 0;
}

It looks like ... shorter?
 
S

stf

Yes.



Yes. It is undefined behavior if you return pointers to parts of local
objects.


No. Use std::string and dump your BufferWrapper.

#include <iostream>
#include <string>

using namespace std;

typedef std::string BufferWrapper;

void testMethod(const BufferWrapper& s) {
cerr << "testMethod: " << s.c_str() << endl;
}

int main() {
testMethod("test string"); // implicit constructor
return 0;
}

It looks like ... shorter?

Yeah sure but this BufferWrapper was just an example (it is more
complicated here than this).

Thanks.

STF
 
Ö

Öö Tiib

Yeah sure but this BufferWrapper was just an example (it is more
complicated here than this).

Yes, but you are basically using that temporary object like conversion
function that for some reason keeps the goods inside it instead of
returning right back. You do not want to pass its input directly and
also you have nothing to do with that converter. So write a function
that returns what you want. About std::string or std::vector<char> i
was serious ... these are far better things for transporting bytes
around than char* is.
 
S

stf

Yes, but you are basically using that temporary object like conversion
function that for some reason keeps the goods inside it instead of
returning right back. You do not want to pass its input directly and
also you have nothing to do with that converter. So write a function
that returns what you want.

This is "Resource Acquisition Is Initialization" idiom... The point
is that BufferWrapper contents get freed automatically after they
are not needed anymore.

So is the case with std::string contents, but as I said: this is not
really char* here.

STF
 
Ö

Öö Tiib

This is "Resource Acquisition Is Initialization" idiom... The point
is that BufferWrapper contents get freed automatically after they
are not needed anymore.

So is the case with std::string contents, but as I said: this is not
really char* here.

Origin of your problem was BufferWrapper and its lifetime. Your main()
did not want to have BufferWrapper objects nor did your testMethod()
desire BufferWrappers as input. That is why i said your BufferWrapper
is converter function not object. RAII has nothing to do with it.
 
S

stf

Origin of your problem was BufferWrapper and its lifetime. Your main()
did not want to have BufferWrapper objects nor did your testMethod()
desire BufferWrappers as input. That is why i said your BufferWrapper
is converter function not object. RAII has nothing to do with it.

It is a converter but conversion results have to be freed after
being used by testMethod. That's why I use RAII.

STF
 
Ö

Öö Tiib

It is a converter but conversion results have to be freed after
being used by testMethod. That's why I use RAII.

Yes, and so use data with RAII.

#include <iostream>
#include <string>

using namespace std;

string cleanse( const char* dirty ) {
string ret(dirty);
// ... clean ret up
return ret;
}

void testMethod(const string& s) {
cerr << "testMethod: " << s.c_str() << endl;
}

int main() {
const char* gotItFromSomeHole = "test string";
testMethod(cleanse(gotItFromSomeHole));
return 0;
}
 
S

stf

Yes, and so use data with RAII.

#include <iostream>
#include <string>

using namespace std;

string cleanse( const char* dirty ) {
string ret(dirty);
// ... clean ret up
return ret;
}

void testMethod(const string& s) {
cerr << "testMethod: " << s.c_str() << endl;
}

int main() {
const char* gotItFromSomeHole = "test string";
testMethod(cleanse(gotItFromSomeHole));
return 0;
}

Yeah, sure but this requires a copy constructor and sometimes the
conversion itself is handled by something else (and you don't know
the structure of the resulting data).

STF
 
Ö

Öö Tiib

Yeah, sure but this requires a copy constructor
Where?

and sometimes the
conversion itself is handled by something else (and you don't know
the structure of the resulting data).

Huh. Something there is that you know. Otherwise you can not use it in
your software. To achieve RAII with C-style information hiding use
boost::shared_ptr or std::tr1::shared_ptr. You have to give proper
deleter to shared_ptr constructor and there you have your safe wrapper
with RAII.
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top