ctor, operator =

M

marbac

Hello,

i defined an overloaded operator = for my class which works perfect
outside of my class.

In this case, is following ctor valid?

test::test (const test& src){
*this=src;
}

Thanks and regards
marbac
 
A

Andrey Tarasevich

marbac said:
...
i defined an overloaded operator = for my class which works perfect
outside of my class.

In this case, is following ctor valid?

test::test (const test& src){
*this=src;
}
...

In general case - no. Assignment operator is normally applied to the
already constructed object and in general case the implementation of the
assignment operator will rely on that fact. In the code above you are
trying to apply the assignment operator to an object, which has not been
constructed yet. Whether this is a problem in your particular case
depends on your class implementation details.
 
M

marbac

Andrey said:
In general case - no. Assignment operator is normally applied to the
already constructed object and in general case the implementation of the
assignment operator will rely on that fact. In the code above you are
trying to apply the assignment operator to an object, which has not been
constructed yet. Whether this is a problem in your particular case
depends on your class implementation details.

Well i reduced my code to a simple example to show my problem.
And I also found the mistake i made ... what a mess, because
it has nothing to do with the question "
copy constructor with operator = is valid?"

thanks a lot and regards marbac



#include <iostream>

class test {

public:
test (int _size): size(_size) {
if (size>0) array=new int [this->size];
else array=0;

}

test (test& src) {
array=0; // THIS WAS MISSING!!
*this=src;
}

~test () {
if (array) delete [] array;
}

test& operator = (const test& src) {
size=src.size;
if (array) delete [] array;
if (size>0) array=new int [this->size];
else array=0;
return *this;
}

void cout_size () {
std::cout << "Size:" << size << std::endl;
}

private:
int *array;
int size;
};


int main () {
test a(4);
test b(5);
test c(6);

a.cout_size();
b.cout_size();
c.cout_size();

a=b;
a.cout_size();

test d (a); //runtime - error if deleting non 0 pointer at construction
time
d.cout_size ();
}
 
K

Kurt Stutsman

marbac wrote:
[snip]
#include <iostream>

class test {

public: [snip]
test& operator = (const test& src) {
size=src.size;
if (array) delete [] array;
if (size>0) array=new int [this->size];
else array=0;
return *this;
}
You should wrap the body of your operator = () in any class like this:
test& operator = (const test& src) {
if(this != &src) {
size=src.size;
if (array) delete [] array;
if (size>0) array=new int [this->size];
else array=0;
}

return *this;
}

Even though above you aren't copying data, just allocating space, I'm gonna
assume you plan to copy data eventually. In which case, the original values in
a.array would have been lost.
 
A

Andrey Tarasevich

marbac said:
...

Well i reduced my code to a simple example to show my problem.
And I also found the mistake i made ... what a mess, because
it has nothing to do with the question "
copy constructor with operator = is valid?"

Well, actually it has everything to do with that question. The problem
you had in your code is exactly what I was talking about. You called
assignment operator for an object, which was not constructed yet (it
contained garbage in 'array' field).
 
R

Ron Natalie

marbac said:
Andrey said:
In general case - no. Assignment operator is normally applied to the
already constructed object and in general case the implementation of the
assignment operator will rely on that fact. In the code above you are
trying to apply the assignment operator to an object, which has not been
constructed yet. Whether this is a problem in your particular case
depends on your class implementation details.


Well i reduced my code to a simple example to show my problem.
And I also found the mistake i made ... what a mess, because
it has nothing to do with the question "
copy constructor with operator = is valid?"

thanks a lot and regards marbac



#include <iostream>

class test {

public:
test (int _size): size(_size) {
if (size>0) array=new int [this->size];
else array=0;

}

test (test& src) {
array=0; // THIS WAS MISSING!!
*this=src;
}

~test () {
if (array) delete [] array;
}

test& operator = (const test& src) {
size=src.size;
if (array) delete [] array;
if (size>0) array=new int [this->size];
else array=0;
return *this;
}

void cout_size () {
std::cout << "Size:" << size << std::endl;
}

private:
int *array;
int size;
};
How about:

class test {
std::vector<int> array;
public:
test(int size) : array(size) { }
void cout_size() { std::cout << "Size: " << array.size() << "\n"; }
};

Let vector do the work. No extra effort for destruction or copying.
 
M

marbac

Ron said:
Let vector do the work. No extra effort for destruction or copying.

I thought about using a vector. But i can imagine, that vector
adds a large amount of overhead to the problem.

In my example unacceptable overhead because I am writing a programm
which accesses large scalarfields to make calculations based on the
scalarfield (e.g. make a directional derivative).
 
K

Karl Heinz Buchegger

marbac said:
I thought about using a vector. But i can imagine, that vector
adds a large amount of overhead to the problem.

Have you tried it?
On nearly all std::vector implementations, it is the case that
you don't pay *any* runtime overhead. It may be that std::vector
allocates more memory then absolutely needed. But usually it
is not a problem to program in a way such that this doesn't
happen (or use a std::valarray)
In my example unacceptable overhead because I am writing a programm
which accesses large scalarfields to make calculations based on the
scalarfield (e.g. make a directional derivative).

As said: std::vector usually behaves very much the same then anything
you can come up with by yourself with respect to runtime. Sometimes
it happens that std::vector outperforms a homemade implementation.
 
M

marbac

Karl said:
Have you tried it?

Good Question.Yes, I have. The Results are, that accessing
int-elements on vector takes more than twice the time in comparison with
accessing int-elements of an array (just write/read) using gcc.
I didn`t use valarray yet ... would be interesting to know how it behaves.
 
K

Karl Heinz Buchegger

marbac said:
Good Question.Yes, I have. The Results are, that accessing
int-elements on vector takes more than twice the time in comparison with
accessing int-elements of an array (just write/read) using gcc.

Did you test a debug or a release build?
It is not uncommon, that debug builds execute slower. But all
of this turns around, once the compiler is allowed to do some
optimizations.
 
M

marbac

Karl said:
Did you test a debug or a release build?
It is not uncommon, that debug builds execute slower. But all
of this turns around, once the compiler is allowed to do some
optimizations.
Hi,

g++ -O3 ...
gives me the same time for both tests.

Thanks
marbac
 
R

Ron Natalie

marbac said:
Hi,

g++ -O3 ...
gives me the same time for both tests.

Thanks
marbac

The specific issue is that the debug mode disables inlining.
That's what usually kills the C++ library performance as the
operator[] plus lots of other tiny functions that should be
inlined don't get done.
 
M

marbac

Karl said:
Could you post your test program.
Your timeing is quite unusual.

Sure, but it seems, that i have to get deeper into vectors than i
wanted, because i played a little bit with the 2 #defines ...



#include <ctime>
#include <vector>
#include <iostream>

#define SAMPLES 100000000
#define SIZE 50

using namespace std;

int main () {

int *intptr;
int tmpint;
vector <int> intvector;
time_t start,stop;

time(&start);
for (int tmp=0; tmp<SAMPLES; tmp++){
intptr=new int[SIZE];
for (int tmp2=0; tmp2<SIZE;tmp2++) intptr[tmp2]=tmp2;
for (int tmp2=0; tmp2<SIZE;tmp2++) tmpint=intptr[tmp2];
delete [] intptr;
}

time(&stop);

cout << "Test1: " << difftime(stop,start) << " s" << endl;

time(&start);
for (int tmp=0; tmp<SAMPLES; tmp++){
for (int tmp2=0; tmp2<SIZE;tmp2++) intvector.push_back(tmp2);
for (int tmp2=0; tmp2<SIZE;tmp2++) tmpint=intvector[tmp2];
intvector.clear();
}
time(&stop);

cout << "Test2: " << difftime(stop,start) << " s" << endl;
}
 
K

Karl Heinz Buchegger

marbac said:
Sure, but it seems, that i have to get deeper into vectors than i
wanted, because i played a little bit with the 2 #defines ...

Hmm. You are not comparing the time values for vector
and plain int arrays.

Well. Your benchmark is not fair.
For one, you allocate the int array in one big rush, while
you depend on the vector to enlarge itself whenever needed.
That's 2 completely different operations, since the vector
has to do additional operations to ensure that you don't
overflow it. If you need to add that functionality to your
own dynamically allocated array, it would slow down also.

But it can be cured easily. Just tell the vector
how many integers it should expect

time(&start);
for ( tmp=0; tmp<SAMPLES; tmp++){
vector <int> intvector( SIZE );
for (int tmp2=0; tmp2<SIZE;tmp2++) intvector[tmp2]=tmp2;
for ( tmp2=0; tmp2<SIZE;tmp2++) tmpint=intvector[tmp2];
}
time(&stop);

With this modification, the allocated array and the vector are on a near
tie on my system.
 
M

marbac

Karl said:
But it can be cured easily. Just tell the vector
how many integers it should expect

time(&start);
for ( tmp=0; tmp<SAMPLES; tmp++){
vector <int> intvector( SIZE );
for (int tmp2=0; tmp2<SIZE;tmp2++) intvector[tmp2]=tmp2;
for ( tmp2=0; tmp2<SIZE;tmp2++) tmpint=intvector[tmp2];
}
time(&stop);

With this modification, the allocated array and the vector are on a near
tie on my system.

Hi,

i investigated a little bit more time into this issue after your last
posting, because i also need a method to measure the efficiency of
sorting-algorithms

I had to rewrite your method a little bit for this test (vector resize).
I also took the architekturespecific rdtsc as timing reference, after i
was looking for a more precice method to catch the time. It might be not
standard conform from now on ... maybe [OT][OT]



Open issues: Huge Peaks -> out of process time-slice?

Regards marbac



#include <iostream>
#include <asm/msr.h> //not part of the standard ... found nothing
#include <vector>



using namespace std;

unsigned long int cyclecount() { //own time not eliminated
union {
unsigned int a[2];
unsigned long int b;
} tmp;
rdtsc(tmp.a[0],tmp.a[1]);
return tmp.b;
}

int main () {

int *intptr;
int tmpint;
vector <int> intvector;
unsigned long int start,stop;


for (int SIZE=1; SIZE<5000000; SIZE+=100000) {

start=cyclecount();
intptr=new int[SIZE];
for (int tmp2=0; tmp2<SIZE;tmp2++) intptr[tmp2]=tmp2;
for (int tmp2=0; tmp2<SIZE;tmp2++) tmpint=intptr[tmp2];
delete [] intptr;
stop=cyclecount();

cout << SIZE<<";" << stop-start << ";";

start=cyclecount();
for (int tmp2=0; tmp2<SIZE;tmp2++)
intvector.push_back(tmp2);
for (int tmp2=0; tmp2<SIZE;tmp2++)
tmpint=intvector[tmp2];
intvector.clear();
stop=cyclecount();

cout << stop-start << ";" ;

start=cyclecount();
intvector.resize( SIZE );
for (int tmp2=0; tmp2<SIZE;tmp2++) intvector[tmp2]=tmp2;
for (int tmp2=0; tmp2<SIZE;tmp2++)
tmpint=intvector[tmp2];
intvector.clear();
stop=cyclecount();

cout << stop-start << endl;
}
}


Results in CSV:

SIZE;PTRARRAY;VECPUSH;VEC[]
1;90240;33813;2654
100001;1896656;5664987;3146048
200001;4230510;9652769;6954714
300001;6560475;19215142;10414353
400001;8369995;8882148;15616197
500001;10558827;11020351;17199550
600001;12684491;37278433;20708852
700001;15086101;16791983;24092673
800001;17071504;19370898;28661935
900001;21307146;20523950;31445133
1000001;23156010;20607862;34606138
1100001;25174683;73625877;59363345
1200001;69786689;24653751;44094400
1300001;29101467;26656635;44958542
1400001;31332855;28733868;48584683
1500001;33332168;30702743;52032413
1600001;35405227;32930185;55892739
1700001;37700109;34945367;58622792
1800001;39462811;36891294;62915030
1900001;41600231;38950686;65648007
2000001;43695271;42831192;69223034
2100001;49232075;128685758;72172464
2200001;50027132;44577776;75539856
2300001;52210913;47116775;79139642
2400001;54281571;48872439;82872617
2500001;57062003;50617815;85639494
2600001;58712443;52762684;89109782
2700001;60791390;54667671;92389609
2800001;62956952;56679381;96426701
2900001;64791646;58617808;100038896
3000001;66694691;60873717;104918710
3100001;69668862;63589150;105669219
3200001;71590029;64368308;108763045
3300001;73443406;66443554;114306131
3400001;75971787;68211420;115523403
3500001;77243384;70734080;119151197
3600001;79104939;73109602;122264614
3700001;82405595;74260025;127104789
3800001;82316763;76214869;131076252
3900001;83774542;79485742;133650033
4000001;87420350;80137556;135647762
4100001;89002910;82514142;139303053
4200001;92127870;255667184;143994369
4300001;93281569;87342295;147955058
4400001;95212196;90756951;150916301
4500001;102373012;92316403;154436919
4600001;99994411;93167989;157996168
4700001;104611956;96599927;160801089
4800001;104253083;97598571;164166263
4900001;108748142;99228504;168168065
 

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
474,202
Messages
2,571,057
Members
47,662
Latest member
sxarexu

Latest Threads

Top