Same name parameter and data member initialization

N

Nagrik

Hello Group,

How do I initialize a char* data member, if the parameter is also the
same as
that of data member.

class A {

private:

int id;
double pay;
char* name;

public:

A(int id, double pay, char* name ) : id(id), pay(pay) // OK
// Can not initialize name since memory is
not allocated

{

this->name = new char[strlen(name) + 1]; // Can not use "this"
pointer

// because "this" pointer will only exist after the constructor is
called.

}


};

Thanks.

nagrik
 
I

Ian Collins

Nagrik said:
Hello Group,

How do I initialize a char* data member, if the parameter is also the
same as
that of data member.

class A {

private:

int id;
double pay;
char* name;

public:

A(int id, double pay, char* name ) : id(id), pay(pay) // OK
// Can not initialize name since memory is
not allocated

{

this->name = new char[strlen(name) + 1]; // Can not use "this"
pointer
You can, doing so is a perfectly good way of disambiguating the names.

You should consider using a std::string, which saves you the trouble of
managing the buffer.
 
A

Andrey Tarasevich

Nagrik said:
...
// because "this" pointer will only exist after the constructor is
called.
...

There's nothing wrong with using 'this' pointer inside constructor. It
does exist. What made you think it didn't?

Your code looks OK.
 
C

Christopher Pisz

Nagrik said:
Hello Group,

How do I initialize a char* data member, if the parameter is also the
same as
that of data member.

class A {

private:

int id;
double pay;
char* name;

public:

A(int id, double pay, char* name ) : id(id), pay(pay) // OK
// Can not initialize name since memory is
not allocated

{

this->name = new char[strlen(name) + 1]; // Can not use "this"
pointer

// because "this" pointer will only exist after the constructor is
called.

}


};

Thanks.

nagrik




A lot of people prefix member data with m_ to tell the difference, but it is
a style rather than mandate.

class Foo
{
std::string m_name

public:
Foo(const std::string & name)
:
m_name(name)
{}
};
 
P

pelio

Nagrik a écrit :
Hello Group,

How do I initialize a char* data member, if the parameter is also the
same as
that of data member.

class A {

private:

int id;
double pay;
char* name;

public:

A(int id, double pay, char* name ) : id(id), pay(pay) // OK

You can declare a variable with the name of an already declared if are
declared in different scope.
// Can not initialize name since memory is
not allocated

{

this->name = new char[strlen(name) + 1]; // Can not use "this"
pointer

// because "this" pointer will only exist after the constructor is
called.

When constructor is called, memory is already allocated and "this" is valid.
 
J

James Kanze

How do I initialize a char* data member, if the parameter is
also the same as that of data member.

The same way you'd initialize any other data member.
class A {

int id;
double pay;
char* name;

A(int id, double pay, char* name ) : id(id), pay(pay) // OK
// Can not initialize name since
// memory is not allocated

So allocate it:

, name( new char[ strlen( name ) + 1 ] )

Or better yet:

, name( duplicateString( name ) )

with the necessary functionality in duplicateString.
this->name = new char[strlen(name) + 1]; // Can not use "this" pointer
// because "this" pointer will only exist after the
// constructor is called.

I don't know where you got that from. The this pointer is valid
in any member function, including the constructor.

Of course, if you used std::string, the code would be even
simpler and easier to maintain.
 
G

Grizlyk

James said:
So allocate it:

    ,name( new char[ strlen(name) + 1 ] )

Or better yet:

    ,name( duplicateString(name) )

with the necessary functionality in duplicateString.

Note, the code is unsafe for exceptions (in generic case). With the
kind of pointers you need ideally two-stage sequence of initializing:

A::A(int id, double pay, char* name ): // auto: //:)
id(id),
pay(pay),

//first stage
//here zero for delete[] safe
name(0)
{
//second stage
A::name=new char[ strlen(name) + 1 ];
}

but since C++ does not support control of auto/noauto destructor
calls, you can do like this:

//dtor replacement
A::do_delete(){ delete[] name; }

//dtor
A::~A(){ do_delete(); }

//will call dtor
A& A::eek:perator= (const A&);

//will call dtor replacement
A::A(int id, double pay, char* name ):
id(id),
pay(pay),
//first stage
//here zero for delete[] safe
name(0)
{
try{
//second stage
A::name=new char[ strlen(name) + 1 ];
...
}
catch(...){ do_delete(); throw; }
}

Appropriate RAII wrapper instead of POD pointers is safe for
exceptions for current-style code.

POD pointers as member of class can be found, for example, while
porting old-style code without exceptions into old-style code with.

You probably can use (or write) a wrapper to replace POD pointer
behaviour for the kind of code instead of two-stage initializing (to
do porting old-style code without exceptions into new-style code
with).

Once I have refused from any of the porting because of not-stacked C++
exceptions:

class A
{
Internal a,b;

~A()
{
//can throw during throw
Closer closer:):external,a,b);
closer.do();
}
};

The possible runtime error here is very hard to detect at compile
time, because "Closer" is general-purpose class - is not developed to
be used for destructors only and whole code has not been written for
"no any destructors for non-wrapper class" paradigm :)

Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new
 
J

James Kanze

James Kanze wrote:
So allocate it:
,name( new char[ strlen(name) + 1 ] )
Or better yet:
,name( duplicateString(name) )
with the necessary functionality in duplicateString.
Note, the code is unsafe for exceptions (in generic case).

It depends on what you mean by "generic case". In the orignal
example, the code was exception safe, and if the above is used
to replace the original example, it is also exception safe.

If the class contains several such pointers, of course, you'll
probably want to factor them out into as many base classes or
smart pointers. boost::scoped_ptr is very good for this, and
std::auto_ptr can also be used. Except, of course, that here,
we are talking about a dynamic array---in almost all cases,
std::string or std::vector< char > would be used, e.g.:
std::vector< char > name ;
and
, name( name, name + strlen( name ) + 1 )
,for example.)
With the kind of pointers you need ideally two-stage sequence
of initializing:
A::A(int id, double pay, char* name ): // auto: //:)
id(id),
pay(pay),
//first stage
//here zero for delete[] safe
name(0)
{
//second stage
A::name=new char[ strlen(name) + 1 ];
}

Which doesn't change anything with regards to my suggestion
(except make the code more complex and more difficult to
understand).
but since C++ does not support control of auto/noauto destructor
calls, you can do like this:
//dtor replacement
A::do_delete(){ delete[] name; }
//dtor
A::~A(){ do_delete(); }
//will call dtor
A& A::eek:perator= (const A&);
//will call dtor replacement
A::A(int id, double pay, char* name ):
id(id),
pay(pay),
//first stage
//here zero for delete[] safe
name(0)
{
try{
//second stage
A::name=new char[ strlen(name) + 1 ];
...
}
catch(...){ do_delete(); throw; }
}

Which is doing things the hard way, and totally unnecessary in
the case in question.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top