473,394 Members | 1,870 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

Pitfalls and problems in this code?

I hate it when people reinvent the wheel. This is some legacy code that
I believe may be causing some memory issues. I think there may be a
problem in the way that the CVector class is kill_resize'd or assigned.
Any thoughts?

class CVector
{
// types:
public:
typedef double data_type;

// Constructors
public:
CVector();
CVector(long source_length);
CVector(long source_length, const data_type* const source_data);
CVector(const CVector &fil);
virtual ~CVector();

// Operators
public:
CVector& operator= (const CVector& source);

// Functions
public:
data_type* begin() const { return data; };
data_type* end() const { return data + length; };
long size() const { return length; };
bool empty() const { return size() == 0; }

// set new vector length _without_ copying
void kill_resize (long source_length);

data_type* data;

// Member variables:
protected:
long length;
};
// Constructors:
CVector::CVector(): data(0), length(0) {}

CVector::CVector(long source_length):
length(source_length), data(new data_type[source_length]) {}

CVector::CVector(long source_length, const data_type* const source_data):
length(source_length), data(new data_type[source_length])
{
if (data) memcpy(data, source_data, length * sizeof(data_type));
}

CVector::CVector(const CVector &v):
length(v.length), data(new data_type[v.length])
{
if (data) memcpy(data, v.data, length * sizeof(data_type));
}

// Destructor
CVector::~CVector()
{
if (data) delete[] data;
data = 0; // do not free again.
length = 0;
}

/////////////////////////////////////////////////////////////////////////////////////////

// Change the length of an existing vector WITHOUT COPYING

void CVector::kill_resize (long source_length)
{
if (data && (source_length != length))
{
delete[] data; // there was something in here
data = 0; // do not free again.
}

if (!data) data = new data_type[source_length]; // get memory
length = source_length;
}

/////////////////////////////////////////////////////////////////////////////////////////

CVector& CVector::operator= (const CVector &source)
{
if (source.data == NULL) {
if (data != NULL) {
delete[] data; // there was something in here
data = 0; // do not free again.
}
length = 0;

return *this;
}

if (data == source.data) {
return *this;
}

kill_resize (source.length);
if (source.data) memcpy(data, source.data, length * sizeof(data_type));

return *this;
}
Sep 26 '05 #1
6 1391
Bryan wrote:
I hate it when people reinvent the wheel. This is some legacy code that
I believe may be causing some memory issues. I think there may be a
problem in the way that the CVector class is kill_resize'd or assigned.
Any thoughts?
Several.
class CVector
{
// types:
public:
typedef double data_type;

// Constructors
public:
CVector();
CVector(long source_length);
CVector(long source_length, const data_type* const source_data);
The second 'const' is superfluous.
CVector(const CVector &fil);
virtual ~CVector();
'virtual'? Do you expect this class to serve as a base class?

// Operators
public:
CVector& operator= (const CVector& source);

// Functions
public:
data_type* begin() const { return data; };
data_type* end() const { return data + length; };
Semicolons after a curly brace are superfluous. Drop 'em.

Are you sure you want to return a pointer to non-const objects for
the data of a [potentially] const CVector? I'd probably declare
those

data_type const* begin() const;
data_type const* end() const;
long size() const { return length; };
bool empty() const { return size() == 0; }

// set new vector length _without_ copying
void kill_resize (long source_length);

data_type* data;
Why is 'data' public?

// Member variables:
protected:
long length;
};
// Constructors:
CVector::CVector(): data(0), length(0) {}

CVector::CVector(long source_length):
length(source_length), data(new data_type[source_length]) {}

CVector::CVector(long source_length, const data_type* const source_data):
length(source_length), data(new data_type[source_length])
{
if (data) memcpy(data, source_data, length * sizeof(data_type));
'data' will never be 0 here unless you use 'new (nothrow) '. If you
don't (like here), an exception 'std::bad_alloc' is thrown if it can't
allocate.

It is generally better to use

std::copy(source_data, source_data + length, data);

instead of 'memcpy'. You will need those everywhere you use 'memcpy' as
soon as you convert your class to be a template (you're going that way,
aren't you?)
}

CVector::CVector(const CVector &v):
length(v.length), data(new data_type[v.length])
{
if (data) memcpy(data, v.data, length * sizeof(data_type));
Same sentiment as above. 'data' is never 0. Don't use 'memcpy'.
}

// Destructor
CVector::~CVector()
{
if (data) delete[] data;
There is no harm in deleting a null pointer.
data = 0; // do not free again.
length = 0;
There is no need to change members of an object being destructed. They
are on their way out.
}

/////////////////////////////////////////////////////////////////////////////////////////
// Change the length of an existing vector WITHOUT COPYING

void CVector::kill_resize (long source_length)
{
if (data && (source_length != length))
{
delete[] data; // there was something in here
data = 0; // do not free again.
}

if (!data) data = new data_type[source_length]; // get memory
For consistency's sake, you ought to check whether the 'data' is still
non-null here. You apparently don't. Well, you don't need to, of course.
length = source_length;
}

/////////////////////////////////////////////////////////////////////////////////////////
CVector& CVector::operator= (const CVector &source)
{
if (source.data == NULL) {
if (data != NULL) {
delete[] data; // there was something in here
data = 0; // do not free again.
}
length = 0;

return *this;
}

if (data == source.data) {
return *this;
}

kill_resize (source.length);
if (source.data) memcpy(data, source.data, length * sizeof(data_type));

return *this;
}


Well, I don't see anything particularly bad here, but there is still
a possibility of dissinchronization between 'data' and 'length'. I would
recommend adding something like

assert((data != 0) == (length > 0));

in every function -- that's a consistency check.

V
Sep 26 '05 #2
* Bryan:
I hate it when people reinvent the wheel. This is some legacy code that
I believe may be causing some memory issues. I think there may be a
problem in the way that the CVector class is kill_resize'd or assigned.
Any thoughts?

class CVector
{
// types:
public:
typedef double data_type;
Seems this was aimed at later templatizing.

// Constructors
public:
CVector();
CVector(long source_length);
CVector(long source_length, const data_type* const source_data);
CVector(const CVector &fil);
virtual ~CVector();

// Operators
public:
CVector& operator= (const CVector& source);

// Functions
public:
data_type* begin() const { return data; };
data_type* end() const { return data + length; };
Destroys logical constness.

long size() const { return length; };
bool empty() const { return size() == 0; }

// set new vector length _without_ copying
void kill_resize (long source_length);

data_type* data;
Public data how nice.

// Member variables:
protected:
long length;
Seems inconsistent with the access for 'data'.

};
// Constructors:
CVector::CVector(): data(0), length(0) {}

CVector::CVector(long source_length):
length(source_length), data(new data_type[source_length]) {}

CVector::CVector(long source_length, const data_type* const source_data):
length(source_length), data(new data_type[source_length])
{
if (data) memcpy(data, source_data, length * sizeof(data_type));
}
The 'if' is superflous.

CVector::CVector(const CVector &v):
length(v.length), data(new data_type[v.length])
{
if (data) memcpy(data, v.data, length * sizeof(data_type));
}
The 'if' is superflous.

// Destructor
CVector::~CVector()
{
if (data) delete[] data;
data = 0; // do not free again.
length = 0;
}

/////////////////////////////////////////////////////////////////////////////////////////

// Change the length of an existing vector WITHOUT COPYING

void CVector::kill_resize (long source_length)
{
if (data && (source_length != length))
{
delete[] data; // there was something in here
data = 0; // do not free again.
}

if (!data) data = new data_type[source_length]; // get memory
length = source_length;
}
If data != 0 were made a class invariant (simply fix the default constructor)
the logic above would be equivalent to

if( source_length != length )
{
delete[] data; // there was something in here
data = new data_type[source_length]; // get memory
}
length = source_length;

which seems to be correct.

Note that kill_resize guarantees data != 0 on exit.

/////////////////////////////////////////////////////////////////////////////////////////

CVector& CVector::operator= (const CVector &source)
{
if (source.data == NULL) {
if (data != NULL) {
delete[] data; // there was something in here
data = 0; // do not free again.
}
length = 0;

return *this;
}
If data != 0 were made a class invariant (simply fix the default constructor)
the above would never happen and that code could be removed.

if (data == source.data) {
return *this;
}
This avoids self-assignment in a round-about way, OK.

kill_resize (source.length);
if (source.data) memcpy(data, source.data, length * sizeof(data_type));
The 'if' is superflous. The code at the top of this function guarantees
source.data != 0. And the call to kill_resize guarantees data != 0.

return *this;
}


--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Sep 26 '05 #3

Alf P. Steinbach wrote:
public:
data_type* begin() const { return data; };
data_type* end() const { return data + length; };


Destroys logical constness.


For our (mine) education, could you elaborate?

I'm unfamiliar with the term "logical constness" and do not understand
what is wrong with the code fragment.

Thanks,
Andre

Sep 26 '05 #4
in*****@gmail.com wrote:
Alf P. Steinbach wrote:
public:
data_type* begin() const { return data; };
data_type* end() const { return data + length; };


Destroys logical constness.

For our (mine) education, could you elaborate?

I'm unfamiliar with the term "logical constness" and do not understand
what is wrong with the code fragment.


class A {
int *pa;
public:
A(int a_) : pa(new int(a_)) {}
A(const A& aa) : pa(new int(*aa.pa)) {}
~A() { delete pa; }

int* get_a() const { return pa; } // BAD!
};

int main() {
A const a_const(42); // is 'a_const' actually const?
int* pi = a_const.get_a();
*pi = 73; // KABOOM!
// I just changed the "value" of a const object
}

Logical constness means that if I declare an object 'const', none of its
parts (including the contents of the dynamic memory it allocates) should
be changeable.

V
Sep 26 '05 #5
Victor Bazarov wrote:
in*****@gmail.com wrote:
Alf P. Steinbach wrote:
public:
data_type* begin() const { return data; };
data_type* end() const { return data + length; };
Destroys logical constness.


For our (mine) education, could you elaborate?

I'm unfamiliar with the term "logical constness" and do not understand
what is wrong with the code fragment.

class A {
int *pa;
public:
A(int a_) : pa(new int(a_)) {}
A(const A& aa) : pa(new int(*aa.pa)) {}
~A() { delete pa; }

int* get_a() const { return pa; } // BAD!
};

int main() {
A const a_const(42); // is 'a_const' actually const?
int* pi = a_const.get_a();
*pi = 73; // KABOOM!
// I just changed the "value" of a const object
}

Logical constness means that if I declare an object 'const', none of its
parts (including the contents of the dynamic memory it allocates) should
be changeable.


You'll have to argue wehter *pa is part of the pobject or not.
Sep 26 '05 #6
Ron Natalie wrote:
Victor Bazarov wrote:
in*****@gmail.com wrote:
Alf P. Steinbach wrote:

> public:
> data_type* begin() const { return data; };
> data_type* end() const { return data + length; };

Destroys logical constness.


For our (mine) education, could you elaborate?

I'm unfamiliar with the term "logical constness" and do not understand
what is wrong with the code fragment.


class A {
int *pa;
public:
A(int a_) : pa(new int(a_)) {}
A(const A& aa) : pa(new int(*aa.pa)) {}
~A() { delete pa; }

int* get_a() const { return pa; } // BAD!
};

int main() {
A const a_const(42); // is 'a_const' actually const?
int* pi = a_const.get_a();
*pi = 73; // KABOOM!
// I just changed the "value" of a const object
}

Logical constness means that if I declare an object 'const', none of its
parts (including the contents of the dynamic memory it allocates) should
be changeable.

You'll have to argue wehter *pa is part of the pobject or not.


No, I won't have to argue, unless you make me argue. Read my definition
of logical constness. The OP asked what it was, I explained. That's the
definition both I and Alf used when claiming the semantical misgivings of
the OP's code. There can be another (your, for example, whatever it is)
definition of "logical constness". I've never claimed mine to be the only
true one.

V
Sep 26 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

16
by: Sims | last post by:
Hi, I am using setcookies to store one single value. But i was reading http://za2.php.net/manual/en/function.setcookie.php and i noticed that a cookie might not be accepted yet it might return...
2
by: wellington fan | last post by:
Dear newsies, My ISP has offered to upgrade my servers from 3.23 to 4.1. I'm excited by the potential gains in performance, and the ability to write subqueries, but am wary of any forward...
4
by: Mantorok Redgormor | last post by:
Should I just avoid them? I have heard many bad things about them 1) if you set a signal handler, you can't really ignore the signal and continue with normal program execution, because after that...
41
by: Greenhorn | last post by:
Hi, We see that C is a bit liberal towards non-standard syntax, for e.g. when i tried <printf("string1", "string2 %d", v1);> in Dev-C++, it printed string1 and no error was raised, is this the...
1
by: spamfurnace | last post by:
Hello. I have a common area of a website that sales agents use. I got sick and tired of typing response.redirect(path) so i implemented a shared function in Global that i can call and all i have...
9
by: Juan T. Llibre | last post by:
This article by Jeff Prosise is a must-read for ASP.NET programmers: http://msdn.microsoft.com/msdnmag/issues/06/07/webappfollies/default.aspx Juan T. Llibre, asp.net MVP aspnetfaq.com :...
3
by: abbu | last post by:
Hi All, I have just finished my graduation. I'am attending my interviews for software companies. If any one has the book "C Traps and Pitfalls" please send it as attachment across to my mail...
5
by: kevincw01 | last post by:
I've got this homework assignment where I need to send some data over a simulated network. Don't worry, I dont want someone to write the code for me, just wondering if there are problems with the...
6
Markus
by: Markus | last post by:
Things to discuss: Headers What are they? What does PHP have to do with headers? Why can they only be sent before any output? Common causes
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.