Constructor with pointer as parameter

G

George

Hi all.

How can I check and return an error on a constructor that receives a
pointer as a parameter and the parameter is null.
Is there any possibility to return an error? or do I have to create
another extra function to construct the class?
What is the common procedure?

TA.

i.e.:

class A {
char *m_name;
A(char *name, int len);
}

A::A(char *name, int len) ´
if (!name) {
ERROR;
}
m_name = new char[len];
memcpy(m_name, name, len);
......
}
 
M

Markus Grueneis

George said:
Hi all.

How can I check and return an error on a constructor that receives a
pointer as a parameter and the parameter is null.
Is there any possibility to return an error? or do I have to create
another extra function to construct the class?
What is the common procedure?

Use exceptions. For instance:

struct bad_argument : std::exception {
bad_argument(const char* what) : std::exception(what) {}
};

class A {
char *m_name;
public:
A(char *name, int len)
{
if(!name)
throw bad_argument();
//...
}
};

But I would encourage you to *not* use char* yet, just use strings, and
be happy with it. There may be some value on using those 'raw types',
but I would recommend using C++ containers where possible.

Then you could do like this:

class A {
std::string m_name;
public:
A(const string &name) // len omitted, string does this itself!
{
// now you can be sure you got a valid string
}
};



best regards,
-- Markus
TA.

i.e.:

class A {
char *m_name;
A(char *name, int len);
}

A::A(char *name, int len) Ž
if (!name) {
ERROR;
}
m_name = new char[len];
memcpy(m_name, name, len);
......
}
 
M

Markus Grueneis

Markus said:
George said:
Hi all.

[...]
>>
Use exceptions. For instance:

struct bad_argument : std::exception {
bad_argument(const char* what) : std::exception(what) {}
};

Sorry for this, as I hadn't given a default argument to 'what', the
usage sample below would not work. Use this instead:

struct bad_argument : std::exception {
bad_argument(const char* what="passed invalid value as argument")
: std::exception(what) {}
};
class A {
char *m_name;
public:
A(char *name, int len)
{
if(!name)
throw bad_argument();
//...
}
};

But I would encourage you to *not* use char* yet, just use strings, and
be happy with it. There may be some value on using those 'raw types',
but I would recommend using C++ containers where possible.

Then you could do like this:

class A {
std::string m_name;
public:
A(const string &name) // len omitted, string does this itself!
{
// now you can be sure you got a valid string
}
};



best regards,
-- Markus

[...]
 
G

George

Use exceptions. For instance:

struct bad_argument : std::exception {
bad_argument(const char* what) : std::exception(what) {}
};

class A {
char *m_name;
public:
A(char *name, int len)
{
if(!name)
throw bad_argument();
//...
}
};

No other way without exceptions?
But I would encourage you to *not* use char* yet, just use strings, and
be happy with it. There may be some value on using those 'raw types',
but I would recommend using C++ containers where possible.

Then you could do like this:

class A {
std::string m_name;
public:
A(const string &name) // len omitted, string does this itself!
{
// now you can be sure you got a valid string
}
};

The *char was just an example. It could be whatever other thing you can
imagine.
Concerning the string - char, I'm still getting in touch with c++ and I
find more and more differences with c every day ;).

Thanks for the quick response.

best regards,
-- Markus
TA.

i.e.:

class A {
char *m_name;
A(char *name, int len);
}

A::A(char *name, int len) Ž
if (!name) {
ERROR;
}
m_name = new char[len];
memcpy(m_name, name, len);
......
}
 
G

George

Markus said:
George said:
Hi all.

[...]
Use exceptions. For instance:

struct bad_argument : std::exception {
bad_argument(const char* what) : std::exception(what) {}
};

Sorry for this, as I hadn't given a default argument to 'what', the
usage sample below would not work. Use this instead:

struct bad_argument : std::exception {
bad_argument(const char* what="passed invalid value as argument")
: std::exception(what) {}
};

Thanks.

BTW this is another question do you know how can I return a pointer to an
array not allowing to change the values it stores?

ie: (the use of char is just as an example, don't change it to string ;))
)

class A {
char *getName();
}

main() {
A a();
char *data = a.getName();
data[2] = 0x34;
}

Supposing everything is well initialize. I want that the values cannot be
changed. By setting const char *getName() I manage to do so, but doing
the following trick you can override it:
const char *data = a.getName();
char *data2 = (char *) data;
data[2] = 0x34;

Any idea?

See you..

Have a nice weekend.


class A {
char *m_name;
public:
A(char *name, int len)
{
if(!name)
throw bad_argument();
//...
}
};

But I would encourage you to *not* use char* yet, just use strings, and
be happy with it. There may be some value on using those 'raw types',
but I would recommend using C++ containers where possible.

Then you could do like this:

class A {
std::string m_name;
public:
A(const string &name) // len omitted, string does this itself!
{
// now you can be sure you got a valid string
}
};



best regards,
-- Markus

[...]
 
R

Rolf Magnus

George said:
BTW this is another question do you know how can I return a pointer to an
array not allowing to change the values it stores?

Make it a pointer to const.
ie: (the use of char is just as an example, don't change it to string ;))
)

class A {
char *getName();
}
;

main() {

You forgot the return type here.
A a();
char *data = a.getName();
data[2] = 0x34;
}

Supposing everything is well initialize. I want that the values cannot be
changed. By setting const char *getName() I manage to do so, but doing
the following trick you can override it:
const char *data = a.getName();
char *data2 = (char *) data;
data[2] = 0x34;

Any idea?

C++ gives you features that should prevent you from accidentally shooting
yourself in the foot. Those features are not designed to prevent you from
deliberate sabotage. There is always a way to go around it.
Don't use C style casts, and only ever cast if you know exactly which cast
you need, and why. Especially, never cast just to get the compiler to shut
up.
 
R

Rolf Magnus

George said:
No other way without exceptions?

What's wrong with exceptions?
Another possibility is to add some kind of validity state to your object. So
in your constructor, you could set your object to invalid if the arguments
were incorrect. However, you have to take care to make all member functions
that rely on the validity do nothing if the state is invalid. The standard
C++ stream classes do it like that.
Another possiblility is to move the initialization to an extra member
function (well, it's not exactly initialization anymore then) and just give
your class a default constructor. Then this 'init' member function can
return information about the validity of your arguments.
Concerning the string - char, I'm still getting in touch with c++ and I
find more and more differences with c every day ;).

Well, std::string should be easier to use than raw pointers to char, but if
you come from C, you may have quite some experience with the latter.
 
J

Jens Theisen

George said:
Any idea?

There is no way to make a type const so that a const_cast can't cast the
constness away. The type system is made to aid programmers, not to
thwart the malicious.

Jens
 
M

Markus Grueneis

George said:
[...about exceptions in constructors...]

Thanks.

BTW this is another question do you know how can I return a pointer to an
array not allowing to change the values it stores?

I hope so ;-)
ie: (the use of char is just as an example, don't change it to string ;))
)

class A {
char *getName();
}

main() {
A a();
char *data = a.getName();
data[2] = 0x34;
}

Supposing everything is well initialize. I want that the values cannot be
changed. By setting const char *getName() I manage to do so, but doing
the following trick you can override it:
const char *data = a.getName();
char *data2 = (char *) data;
data[2] = 0x34;

Any idea?

Several. First, as is discussed very often on this newsgroup, there are
differences between:

char *
const char *
char * const
const char * const

char* defines a pointer variable, where the pointer and the pointee may
be changed.

const char* defines a pointer variable, where only the pointer, but not
the content pointed to may be changed.

char* const defines a pointer, where you may change the content, but not
the pointer.

and finally, with const char* const you may not modify anything at all.


But, there are some exceptions: char* gimpf= "blub"; is allowed. But,
don't try to modify the string. It's undefined behaviour. Short note:
just don't modify anything literal in source-code. This is probably the
same in C, at least it's the same in Lisp, but I don't know.


And again: do not use arrays, when you can use a vector<>. A vector is
guaranteed to have continuous memory, and you can therefore pass it's
content to an ordinarily C-function with like this:

std::vector<int> some_data;
some_data.resize(the_length_you_want);
long retval= some_c_func(&some_data[0], some_data.size());

The vector object cares for itself, i.e. deleting it's content when
going out of scope. And you can use all those STL algorithms and iterators.

for_each(some_data.begin(), some_date.end(), some_unary_function);


If you want to return a vector, which contents may not be altered,
return a const&. Still, the caller may just copy the vector, but then,
you don't have to take care about internal datastructures anymore.


Finally, I want to encourage you to read the C++ FAQ on

http://www.parashift.com/c++-faq-lite/

It discusses many troubles you may encounter when coming from C to C++.
Definitely a must-read before writing serious programs, as C++ tends to
be a very bad experince when learning-by-doing-without-reading. On the
other side, once you got the basic ideas (RAII, for the single most
important when you come from C (only my opinion)), it can be quite easy.
See you..

Well, I don't see you, but text, but that's ok for the place we are meeting.
Have a nice weekend.

You too.

Bye,
-- Markus
 
B

Bo Persson

George said:
BTW this is another question do you know how can I return a pointer
to an
array not allowing to change the values it stores?

ie: (the use of char is just as an example, don't change it to
string ;))
)

class A {
char *getName();
}

main() {
A a();
char *data = a.getName();
data[2] = 0x34;
}

Supposing everything is well initialize. I want that the values
cannot be
changed. By setting const char *getName() I manage to do so, but
doing
the following trick you can override it:
const char *data = a.getName();
char *data2 = (char *) data;
data[2] = 0x34;

Any idea?

In this case, you cane return a std::string with a *copy* of the name.
Then we don't care much what is done with the copy!

Another reason to do this, is to add to the abstraction. If you return
a pointer, you must (somewhere) keep the pointed-to object. What if
someone saves the pointer - how long is it valid?

If you return a std::string, you don't have to tell where you got it
from.


Bo Persson
 
B

Bo Persson

George said:
No other way without exceptions?

You could have a parameter that cannot be NULL :), like a reference,
or a std::string, or a std::vector.


Bo Persson
 
J

Jarmo Muukka

Bo Persson said:
You could have a parameter that cannot be NULL :), like a reference,
or a std::string, or a std::vector.


Bo Persson

Reference can be NULL.

void foo( std::string& name )
{
name."any method"(); // will crash, if name was passed in wrong way
}

void test_foo()
{
std::string* name = 0;
foo( *name );
}

JMu
 
B

Bo Persson

Jarmo Muukka said:
Reference can be NULL.

void foo( std::string& name )
{
name."any method"(); // will crash, if name was passed in
wrong way
}

void test_foo()
{
std::string* name = 0;
foo( *name );
}

JMu

The reference cannot be null, in a conforming program. You are not
allowed to dereference the null pointer.


Bo Persson
 
M

Markus Grueneis

Jarmo said:
[...]
You could have a parameter that cannot be NULL :), like a reference,
or a std::string, or a std::vector.


Bo Persson

Reference can be NULL.

void foo( std::string& name )
{
name."any method"(); // will crash, if name was passed in wrong way
}

void test_foo()
{
std::string* name = 0;
foo( *name );
}

I doubt that. I am no language lawyer, but probably the dereference
*name will already cause a segfault or whatever. Probably the standard
says undefined, but I also doubt that your Linux Box will start
installing Windows and write a "knock knock." on the screen ;-)


-- Markus
 
M

Markus Grueneis

Jarmo said:
[...]

Reference can be NULL.

void foo( std::string& name )
{
name."any method"(); // will crash, if name was passed in wrong way
}

void test_foo()
{
std::string* name = 0;
foo( *name );
}

JMu


Sry I forgot to mention, but of course you are absolutly right that
references may be bad, i.e. point to an object that does not exist.

-- Markus
 
J

Jarmo Muukka

Bo Persson said:
The reference cannot be null, in a conforming program. You are not
allowed to dereference the null pointer.


Bo Persson

OK, lets hide the fact that pointer is zero:

void foo( std::string& name )
{
name."any method"();
}

void test_foo( std::string* name )
{
foo( *name );
}

void test_foo()
{
std::string* name = 0;
test_foo( name );
}

JMu
 
B

Bo Persson

Jarmo Muukka said:
OK, lets hide the fact that pointer is zero:

void foo( std::string& name )
{
name."any method"();
}

void test_foo( std::string* name )
{
foo( *name );
}

void test_foo()
{
std::string* name = 0;
test_foo( name );
}

JMu

You are still dereferencing a null pointer.

In a correct (conforming) program, there cannot be a null reference.

There can be references to objects that has been destroyed, but that
is not something for the function taking a reference to worry about.
It just means that there is an error somewhere else in the program.


Bo Persson
 
F

Frederick Gotham

Markus Grueneis posted:
I doubt that. I am no language lawyer, but probably the dereference
*name will already cause a segfault or whatever. Probably the standard
says undefined, but I also doubt that your Linux Box will start
installing Windows and write a "knock knock." on the screen ;-)


There's controversy at the moment regarding whether the following program
exhibits undefined behaviour:

int main()
{
int *p = 0;

*p;
}

Some people argue that it doesn't (something to do with the absence of an
Lvalue-Rvalue conversion or something like that).

Nonetheless, there's a consenus that a reference shall not be null -- the
Standard even expresses this.
 
G

George

George said:
[...about exceptions in constructors...]

Thanks.

BTW this is another question do you know how can I return a pointer
to an array not allowing to change the values it stores?

I hope so ;-)
ie: (the use of char is just as an example, don't change it to string
;)) )

class A {
char *getName();
}

main() {
A a();
char *data = a.getName();
data[2] = 0x34;
}

Supposing everything is well initialize. I want that the values
cannot be changed. By setting const char *getName() I manage to do
so, but doing the following trick you can override it:
const char *data = a.getName();
char *data2 = (char *) data;
data[2] = 0x34;

Any idea?

Several. First, as is discussed very often on this newsgroup, there
are differences between:

char *
const char *
char * const
const char * const

char* defines a pointer variable, where the pointer and the pointee
may be changed.

const char* defines a pointer variable, where only the pointer, but
not the content pointed to may be changed.

char* const defines a pointer, where you may change the content, but
not the pointer.

and finally, with const char* const you may not modify anything at
all.


But, there are some exceptions: char* gimpf= "blub"; is allowed. But,
don't try to modify the string. It's undefined behaviour. Short
note: just don't modify anything literal in source-code. This is
probably the same in C, at least it's the same in Lisp, but I don't
know.


And again: do not use arrays, when you can use a vector<>. A vector
is guaranteed to have continuous memory, and you can therefore pass
it's content to an ordinarily C-function with like this:

std::vector<int> some_data;
some_data.resize(the_length_you_want);
long retval= some_c_func(&some_data[0], some_data.size());

I know for you it is ease to use classes instead of just pointers or
array. The fact is that I always try to make the code to be small in size
and I have been always thinking that a vector class is bigger than just
an array.
The other thing is that I'm trying to use the same library both in C and
C and for that I try to make the code fit the less powerfull language.
The vector object cares for itself, i.e. deleting it's content when
going out of scope. And you can use all those STL algorithms and
iterators.

for_each(some_data.begin(), some_date.end(), some_unary_function);


If you want to return a vector, which contents may not be altered,
return a const&. Still, the caller may just copy the vector, but
then, you don't have to take care about internal datastructures
anymore.


Finally, I want to encourage you to read the C++ FAQ on

http://www.parashift.com/c++-faq-lite/

I'll do it ;)

Thanks very much for the above explanation. Now I see that what I was
doing with const was more or less write. The issue there was that I was
hacking myself ;)
It discusses many troubles you may encounter when coming from C to
C++. Definitely a must-read before writing serious programs, as C++
tends to be a very bad experince when
learning-by-doing-without-reading. On the other side, once you got
the basic ideas (RAII, for the single most important when you come
from C (only my opinion)), it can be quite easy.
See you..

Well, I don't see you, but text, but that's ok for the place we are
meeting.
Have a nice weekend.

You too.

Bye,
-- Markus
 

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
474,296
Messages
2,571,535
Members
48,282
Latest member
Xyprime

Latest Threads

Top