473,216 Members | 1,355 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,216 software developers and data experts.

A problem when using a reference to a vector of a class with a pointer member to an array

Dear Programmers,

I have a class with a pointer to an array. In the destructor, I just
freed this pointer. A problem happens if I define a reference to a
vector of this kind of class. The destruction of the assigned memory
seems to call the class destructor more than once. I don't know the
reason or whether I used the vector class correctly. Attached is my
program. Thanks for your help.

Regards,
Brian

Run Result:
$ ./a.out
done
*** glibc detected *** double free or corruption (top): 0x08fa40a0 ***
Aborted

Code:
#include <iostream>
#include <vector>

using namespace std;

class ArrayWrap
{
public:
char * pt_ch;
ArrayWrap()
{
pt_ch = new char[100];
}
~ArrayWrap() {
delete[] pt_ch; // if delete this statement, no error then,
// but not a reasonable design
}
};

int main()
{
ArrayWrap dum;
ArrayWrap & rdum = dum;
vector<ArrayWrapdummy(10);
vector<ArrayWrap& refdummy = dummy;

cout << "done" << endl;
return 0;
}

Oct 19 '06 #1
11 1880
Brian wrote:
Dear Programmers,

I have a class with a pointer to an array. In the destructor, I just
freed this pointer. A problem happens if I define a reference to a
vector of this kind of class. The destruction of the assigned memory
seems to call the class destructor more than once. I don't know the
reason or whether I used the vector class correctly. Attached is my
program. Thanks for your help.

Regards,
Brian

Run Result:
$ ./a.out
done
*** glibc detected *** double free or corruption (top): 0x08fa40a0 ***
Aborted

Code:
#include <iostream>
#include <vector>

using namespace std;

class ArrayWrap
{
public:
char * pt_ch;
ArrayWrap()
{
pt_ch = new char[100];
}
~ArrayWrap() {
delete[] pt_ch; // if delete this statement, no error then,
// but not a reasonable design
}
};

int main()
{
ArrayWrap dum;
ArrayWrap & rdum = dum;
vector<ArrayWrapdummy(10);
vector<ArrayWrap& refdummy = dummy;

cout << "done" << endl;
return 0;
}
Your wrapper class needs a copy constructor. See the third bullet about
the law of the big three here:

http://www.parashift.com/c++-faq-lit...html#faq-27.10

But, why not just use vector< vector<char or vector<string(see
http://www.parashift.com/c++-faq-lit...tml#faq-34.1)?

Cheers! --M

Oct 19 '06 #2
Thanks a lot. It works. This is a simplified program from my real
work to reproduce the problem. We can't use vector< vector<char or
vector<stringbecause we need to write what the pointer points to as a
whole body to a tape in one unbuffered write() for speed concern. I
don't know any better way.

However, I still don't understand the reason for the need of copy
constructor. During the lunch, I came out of the idea that why I don't
just use a pointer to the established vector in stead of a reference.
To my surprise, it doesn't work either without a copy constructor. I
don't get it. I didn't make any copy, but just made a pointer or a
reference referring to the established vector object. I don't see
where a copy was made. I didn't put anything in the copy constructor
and it still works. Is this a requirement that the standard library
has? Are there some hidden copy operations made when we define a
vector reference or pointer?

Thanks,
Brian

mlimber wrote:
Your wrapper class needs a copy constructor. See the third bullet about
the law of the big three here:

http://www.parashift.com/c++-faq-lit...html#faq-27.10

But, why not just use vector< vector<char or vector<string(see
http://www.parashift.com/c++-faq-lit...tml#faq-34.1)?

Cheers! --M
Oct 19 '06 #3
"Brian" <su******@myrealbox.comwrote in message
news:11**********************@b28g2000cwb.googlegr oups.com...
Thanks a lot. It works. This is a simplified program from my real
work to reproduce the problem. We can't use vector< vector<char or
vector<stringbecause we need to write what the pointer points to as a
whole body to a tape in one unbuffered write() for speed concern. I
don't know any better way.

However, I still don't understand the reason for the need of copy
constructor. During the lunch, I came out of the idea that why I don't
just use a pointer to the established vector in stead of a reference.
To my surprise, it doesn't work either without a copy constructor. I
don't get it. I didn't make any copy, but just made a pointer or a
reference referring to the established vector object. I don't see
where a copy was made. I didn't put anything in the copy constructor
and it still works. Is this a requirement that the standard library
has? Are there some hidden copy operations made when we define a
vector reference or pointer?

Thanks,
Brian

mlimber wrote:
>Your wrapper class needs a copy constructor. See the third bullet about
the law of the big three here:

http://www.parashift.com/c++-faq-lit...html#faq-27.10

But, why not just use vector< vector<char or vector<string(see
http://www.parashift.com/c++-faq-lit...tml#faq-34.1)?

Cheers! --M
Please don't top post. Please supply more context from previous post.

int main()
{
ArrayWrap dum;
ArrayWrap & rdum = dum;
vector<ArrayWrapdummy(10);
// I believe the previous line is your problem

vector<ArrayWrap& refdummy = dummy;

cout << "done" << endl;
return 0;
}

Vectors tend to be a pain this way. It seems (to me) that when you put an
item into a vector it first creates it into a temporary, then copies the
temporary into the vector. So when the temporary gets destroyed, it runs
the destructor and you're hozed.

I've run into this problem before with classes that are not copyable (
unique objects loaded that can't be copied, or are just a waste of time to
copy). The way I've solved this is to make a private copy constructor (so
it *can't* be copied) then to make my vector into pointers.

vector<ArrayWrap*dummy;
for ( i = 0; i < 10; i++ )
ArrayWrap.push_back( new ArrayWrap );
// code

for ( vector<ArrayWrap>::iterator it = ArrayWrap.begin(); it !=
ArrayWrap.end(); ++it )
delete (*it); // double check syntax of this
Oct 19 '06 #4

Jim Langston wrote in message ...
>
vector<ArrayWrap*dummy;
for ( i = 0; i < 10; i++ )
Got a headache today, Jim? Did you mean?

// ArrayWrap.push_back( new ArrayWrap );
dummy.push_back( new ArrayWrap );

// <GBeen there, done that. <G>
>// code
// >for ( vector<ArrayWrap>::iterator it = ArrayWrap.begin(); it !=
// >ArrayWrap.end(); ++it )
for( vector<ArrayWrap*>::iterator it( dummy.begin() ); it !=
dummy.end(); ++it )
delete (*it); // double check syntax of this
Yep, looks same as one I use:
// ------------------------------------
template<class Seqvoid PurgeCon( Seq &cont ){
typename Seq::iterator it;
for( it = cont.begin(); it != cont.end(); ++it ){
delete *it;
*it = 0; // just in case it's called twice.
} // for(it)
} // template<class Seqvoid PurgeCon(Seq&)
// ------------------------------------

PurgeCon( dummy );

--
Bob R
POVrookie
Oct 20 '06 #5
"BobR" <Re***********@worldnet.att.netwrote in message
news:4c*********************@bgtnsc05-news.ops.worldnet.att.net...
>
Jim Langston wrote in message ...
>>
vector<ArrayWrap*dummy;
for ( i = 0; i < 10; i++ )

Got a headache today, Jim? Did you mean?

// ArrayWrap.push_back( new ArrayWrap );
dummy.push_back( new ArrayWrap );

// <GBeen there, done that. <G>
Heh, yeah, nice catch.
>>// code
// >for ( vector<ArrayWrap>::iterator it = ArrayWrap.begin(); it !=
// >ArrayWrap.end(); ++it )
for( vector<ArrayWrap*>::iterator it( dummy.begin() ); it !=
dummy.end(); ++it )
Me and ArrayWrap again instead of dummy. lo.

I notice you use it (dummy.begin()) to construct the iterator. I've never
known I could do this, but does it really save anything?
>
> delete (*it); // double check syntax of this

Yep, looks same as one I use:
// ------------------------------------
template<class Seqvoid PurgeCon( Seq &cont ){
typename Seq::iterator it;
for( it = cont.begin(); it != cont.end(); ++it ){
delete *it;
Yet, here you don't use the initialization, why?
*it = 0; // just in case it's called twice.
} // for(it)
} // template<class Seqvoid PurgeCon(Seq&)
// ------------------------------------

PurgeCon( dummy );

Oct 20 '06 #6

"Brian" <su******@myrealbox.comwrote in message
news:11**********************@b28g2000cwb.googlegr oups.com...
Thanks a lot. It works. This is a simplified program from my real
work to reproduce the problem. We can't use vector< vector<char or
vector<stringbecause we need to write what the pointer points to as a
whole body to a tape in one unbuffered write() for speed concern. I
don't know any better way.
However, I still don't understand the reason for the need of copy
constructor.

Not understanding what you really did (please post your updated class), the
vector requires that your object are copyable, and to make sure no bugs
exist, the objects should be able to be copied safely with no issues. Your
original ArrayWrap class does not satisfy the "safely copyable" requirement
(although it is copyable).

int main()
{
ArrayWrap a;
ArrayWrap b = a;
}

Try this with your original class, or with the class that you have changed
it to. Does this work correctly (i.e. no memory leaks, crashes, double
deletion errors, etc.)? It won't work with your original class, since at
the end of main(), a double deletion error will occur when object a and b
are destroyed.

That's simply what vector is doing, and if there are bugs with the simple
code above, then there will be bugs when vector gets its hands on it.

- Paul

Oct 20 '06 #7

Brian wrote:
Thanks a lot. It works. This is a simplified program from my real
work to reproduce the problem. We can't use vector< vector<char or
vector<stringbecause we need to write what the pointer points to as a
whole body to a tape in one unbuffered write() for speed concern. I
don't know any better way.
When you say "what the pointer points to" are you talking about the
pointer in your ArrayWrap class? If so then what you need does not
preclude you replacing ArrayWrap with vector<charand replacing
vector<ArrayWrapwith vector<vector<char. "What the pointer points
to" in your ArrayWrap class becomes "the contents of a vector<char>".
You can very easily get at the contents of a vector<charfor your
single unbuffered write.

If I have misunderstood you when you say "what the pointer points to"
please clarify as there may still be a better solution.

Gavin Deane

Oct 20 '06 #8

Jim Langston wrote in message ...
>"BobR" wrote in message
>>
Jim Langston wrote in message ...
>>>
vector<ArrayWrap*dummy;
for ( i = 0; i < 10; i++ )

Got a headache today, Jim? Did you mean?
// ArrayWrap.push_back( new ArrayWrap );
dummy.push_back( new ArrayWrap );
// <GBeen there, done that. <G>

Heh, yeah, nice catch.
>>>// code
// >for ( vector<ArrayWrap>::iterator it = ArrayWrap.begin(); it !=
// >ArrayWrap.end(); ++it )
for( vector<ArrayWrap*>::iterator it( dummy.begin() ); it !=
dummy.end(); ++it )

Me and ArrayWrap again instead of dummy. lo.

I notice you use it (dummy.begin()) to construct the iterator. I've never
known I could do this, but does it really save anything?
Sure, if you did it a million times in your program and optimazation was off,
it could save a second in runtime! <GActually, I was just being a
smart-ass.
If you are used to assignment (=), you should be consistant and always use
assignment in your code. Mostly a 'style choice'.

You seldom see:

class Mine{.....};
Mine My = 12345;
.....but, usually:
Mine My(12345);

.....so....

int Num(12345);

.... is my choice of style. <G>
>
>>
>> delete (*it); // double check syntax of this

Yep, looks same as one I use:
// ------------------------------------
template<class Seqvoid PurgeCon( Seq &cont ){
// typename Seq::iterator it;
// for( it = cont.begin(); it != cont.end(); ++it ){

Yet, here you don't use the initialization, why?
Uuuh, old code? Stole the code from someone and didn't change it?

for( typename Seq::iterator it( cont.begin() ); it != cont.end(); ++it){

// typename Seq::iterator it( cont.begin() );
// for( ; it != cont.end(); ++it ){ delete *it; *it = 0; }

Newbies, see:
"Thinking In C++", Volume 2: Practical Programming (Bruce Eckel, Chuck
Allison)
Chap. 5: Templates in Depth (sub "The typename keyword")
http://www.mindview.net/Books/TICPP/...ngInCPP2e.html
.....for why the 'typename' is needed. (or look it up in *your* book)
> delete *it;
*it = 0; // just in case it's called twice.
} // for(it)
} // template<class Seqvoid PurgeCon(Seq&)
// ------------------------------------

PurgeCon( dummy );

[ I'm not a expert, feel free to correct me. ]
--
Bob R
POVrookie
Oct 20 '06 #9
Dear Jim,

Thank you very much. Your explanation is right. It was not the
reference or pointer that caused the problem but the place your pointed
out.

The vector constructor does create a temporary object and copy it to
all the vector members and destroy it. I put some cout statements in
the constructor, copy constructor and destructor and got relevant
information.

I said that when I put nothing in the copy constructor it still works.
I was wrong. It only works when I don't access anything within the
object, otherwise it causes segmentation error because all its members
will have no valid value if nothing was done in the copy constructor.

I attached my updated program below for context and left some comments.
Now I don't need your technique of pointers. I will keep it in mind
in case needed. Thanks a lot.

Regards,
Brian

Jim Langston wrote:
>
Please don't top post. Please supply more context from previous post.

int main()
{
ArrayWrap dum;
ArrayWrap & rdum = dum;
vector<ArrayWrapdummy(10);
// I believe the previous line is your problem

vector<ArrayWrap& refdummy = dummy;

cout << "done" << endl;
return 0;
}

Vectors tend to be a pain this way. It seems (to me) that when you put an
item into a vector it first creates it into a temporary, then copies the
temporary into the vector. So when the temporary gets destroyed, it runs
the destructor and you're hozed.

I've run into this problem before with classes that are not copyable (
unique objects loaded that can't be copied, or are just a waste of time to
copy). The way I've solved this is to make a private copy constructor (so
it *can't* be copied) then to make my vector into pointers.

vector<ArrayWrap*dummy;
for ( i = 0; i < 10; i++ )
ArrayWrap.push_back( new ArrayWrap );
// code

for ( vector<ArrayWrap>::iterator it = ArrayWrap.begin(); it !=
ArrayWrap.end(); ++it )
delete (*it); // double check syntax of this
------------------------------------------------------------------------------------------------------
#include <iostream>
#include <vector>

using namespace std;

class ArrayWrap
{
public:
char * pt_ch;
ArrayWrap()
{
pt_ch = new char[100];
pt_ch[0] = 'b';
cout << "create dummy" << endl;
}

ArrayWrap(const ArrayWrap & AnArray)
{
pt_ch = new char[100]; // this made copy's pt_ch valid
pt_ch[0] = AnArray.pt_ch[0]; // this assigned values to
// the copy.
cout << "copy dummy" << endl;
}

~ArrayWrap()
{
delete[] pt_ch;
cout << "destruct dummy" << endl;
}

int print()
{
cout << pt_ch[0] << endl;
return 1;
}
};

int main()
{
ArrayWrap dum;
vector<ArrayWrapdummy(5); // copy constructor
// is needed here, otherwise
// pt_ch of dummy[i] points
// to destroyed temporary
// ArrayWrap object
vector<ArrayWrap& refdummy = dummy;
vector<ArrayWrap* pdummy;
dummy[0].print(); // this will cause segmentation
// error if copy constructors
// first two statements is omitted
cout << "done" << endl;
return 0;
}

Oct 27 '06 #10

Brian wrote in message ...
>Please don't top post. Please supply more context from previous post.
But, do trim stuff you are not referencing. <G>

>----------------------------------------------------------------------------
--------------------------
>#include <iostream>
#include <vector>
using namespace std;
A logical next step could be to get rid of the "magic numbers".
const int bufsize = 100;
// int const bufsize(100); // another way to write it.

Now, if you decide to change the size of your 'char array', you only need to
change it in one place and it's all taken care of for you. (see changes
below)

>class ArrayWrap{
public:
char * pt_ch;
ArrayWrap(){
// pt_ch = new char[100];
pt_ch = new char[ bufsize ];
pt_ch[0] = 'b';
cout << "create dummy" << endl;
}

ArrayWrap(const ArrayWrap & AnArray){
// pt_ch = new char[100]; // this made copy's pt_ch valid
pt_ch = new char[ bufsize ]; // this made copy's pt_ch valid

pt_ch[0] = AnArray.pt_ch[0]; // this assigned values to
// the copy.
// Since you declared an 'const int' for the buffer size, you could copy
// the whole thing (not just one char) without doing any other 'checks':

for( int i(0); i < bufsize; ++i){ // simple example
pt_ch[ i ] = AnArray.pt_ch[ i ];
} // for(i)
// [ look up 'std::copy', 'memcpy', etc., for other ways. ]
cout << "copy dummy" << endl;
}

~ArrayWrap(){
delete[] pt_ch;
cout << "destruct dummy" << endl;
}

int print()
{
cout << pt_ch[0] << endl;
return 1;
}
};

int main(){
ArrayWrap dum;
If you don't use 'dum', remove that instance. etc..
vector<ArrayWrapdummy(5); // copy constructor
// is needed here, otherwise
// pt_ch of dummy[i] points
// to destroyed temporary
// ArrayWrap object
vector<ArrayWrap& refdummy = dummy;
vector<ArrayWrap* pdummy;
dummy[0].print(); // this will cause segmentation
// error if copy constructors
// first two statements is omitted
cout << "done" << endl;
return 0;
}
--
Bob R
POVrookie
Oct 28 '06 #11
Hi, Gavin,

Sorry for the late reply. I did mean the pointer in my ArrayWrap class
here, which is "pt_ch" in my original program. To my knowledge, we can
only access each member of a vector one by one in stead of a whole
body. How can I use one write to write all values in a vector to a
file?

I attached my old program in case it's lost.

Thanks,
Brian

Gavin Deane wrote:
Brian wrote:
Thanks a lot. It works. This is a simplified program from my real
work to reproduce the problem. We can't use vector< vector<char or
vector<stringbecause we need to write what the pointer points to as a
whole body to a tape in one unbuffered write() for speed concern. I
don't know any better way.

When you say "what the pointer points to" are you talking about the
pointer in your ArrayWrap class? If so then what you need does not
preclude you replacing ArrayWrap with vector<charand replacing
vector<ArrayWrapwith vector<vector<char. "What the pointer points
to" in your ArrayWrap class becomes "the contents of a vector<char>".
You can very easily get at the contents of a vector<charfor your
single unbuffered write.

If I have misunderstood you when you say "what the pointer points to"
please clarify as there may still be a better solution.

Gavin Deane
Code:
#include <iostream>
#include <vector>

using namespace std;

class ArrayWrap
{
public:
char * pt_ch;
ArrayWrap()
{
pt_ch = new char[100];
}
~ArrayWrap() {
delete[] pt_ch; // if delete this statement, no error then,
// but not a reasonable design
}

};

int main()
{
ArrayWrap dum;
ArrayWrap & rdum = dum;
vector<ArrayWrapdummy(10);
vector<ArrayWrap& refdummy = dummy;

cout << "done" << endl;
return 0;
}

Nov 13 '06 #12

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

Similar topics

9
by: J. Campbell | last post by:
I'm comfortable with arrays from previous programming, and understand the advantages of c++ vectors...I just don't understand how to use them :~( Can you help me to use a vector<string> in the...
3
by: Tony Johansson | last post by:
Hello Experts!! I have two small classes called Intvektor and Matris shown below and a main. Class Intvektor will create a one dimension array of integer by allocate memory dynamically as you...
4
by: Alan | last post by:
I have a class, "event_list", derived from the template class "vector." I extended it with a method, "write" for this new class. Here's its definition: class event_list : public vector<Event> {...
20
by: Joe Van Dyk | last post by:
Is there some rule of thumb about when to use pointers to an object and when to use a reference* to an object when a class needs to have objects as data members? Example: class A { B* b_ptr;...
7
by: fakeprogress | last post by:
For a homework assignment in my Data Structures/C++ class, I have to create the interface and implementation for a class called Book, create objects within the class, and process transactions that...
29
by: shuisheng | last post by:
Dear All, The problem of choosing pointer or reference is always confusing me. Would you please give me some suggestion on it. I appreciate your kind help. For example, I'd like to convert a...
15
by: Jess | last post by:
Hello, Sometimes declarations are all what we need when we define/declare classes (or functions?), but sometimes we need definitions. I learned that if we define a class (B) that has an object...
4
by: abir | last post by:
I am matching a template, and specializing based of a template, rather than a single class. The codes are like, template<template<typename T,typename Alloc = std::allocator<T> class pix{ }; ...
9
by: itdevries | last post by:
Hi, I've ran into some trouble with an overloaded + operator, maybe someone can give me some hints what to look out for. I've got my own custom vector class, as a part of that I've overloaded...
1
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
0
by: jianzs | last post by:
Introduction Cloud-native applications are conventionally identified as those designed and nurtured on cloud infrastructure. Such applications, rooted in cloud technologies, skillfully benefit from...
0
by: mar23 | last post by:
Here's the situation. I have a form called frmDiceInventory with subform called subfrmDice. The subform's control source is linked to a query called qryDiceInventory. I've been trying to pick up the...
2
by: jimatqsi | last post by:
The boss wants the word "CONFIDENTIAL" overlaying certain reports. He wants it large, slanted across the page, on every page, very light gray, outlined letters, not block letters. I thought Word Art...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: fareedcanada | last post by:
Hello I am trying to split number on their count. suppose i have 121314151617 (12cnt) then number should be split like 12,13,14,15,16,17 and if 11314151617 (11cnt) then should be split like...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...

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.