Unexpected Pointer Behavior using Vector<Class>

Hey Guys!

Since you were very quick in helping me the last time ...
I have a bug that I've been trying to get rid of the last ~4 hours.

Sorry for the weird IMSoMechLin Name. Its a "[I]mplicit [M]esh-based [So]lver for [Mech]anical Problems - but only [Lin]ear at first ;-).

PROBLEM:

The IMSoMechLin Constructor creates n Nodes and stores them in a vector.
Once it reaches the 2nd created node it starts connecting them with the Conns.
Creating Node 1 -> nothing to connect to.
Creating Node 2 -> Create Conn [Node1,Node2]
Creating Node 3 -> Create Conn [Node2,Node3]
and so on ...
These Conns are stored in a seperate vector<Conn> connectors

The Problem occurs AFTER the first Connector (connecting Node 1 and 2) is created - more specific: the Value of Node1 inside Connector1 gets changed by the
1
2
myConn = new Conn(nodes.at(nodes.size()-2),*myNode);
			connectors.push_back(*myConn);

How can this be? I found out that by randomly adding cout << "Some cout that tries to read a Node Value like: " << connectors[0].getNode1().getX() << endl; sometimes the error disappears or shifts to the second connector or the location of the weird value-changing moves to a different line - for example to the myNode = new Node3D(x,0,0);.

Output

i: 1 left: 0 and right: 10
i: 2 left: 0 and right: 10
i: 2 left: 2.31584e+77 and right: 10
i: 3 left: 2.31584e+77 and right: 10
i: 3 left: 2.17277e-314 and right: 10
i: 4 left: 2.17277e-314 and right: 10
i: 4 left: 2.17277e-314 and right: 10
[Created Connectors]
strain: 0.414214
strain: 0
strain: 0
strain: 0


THANK YOU VERY MUCH!

Here the (imho) relevant code parts.


Node3D.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifndef NODE3D_H_
#define NODE3D_H_

#define PINNED 1
#define UNPINNED  0

#include <iostream>
#include <vector>

class Node3D {
private:
	double x,y,z;
	bool pinned;
public:
	Node3D(double ax, double ay, double az);
	Node3D(double ax, double ay, double az, int apinned);
	double getDistance(Node3D & an);
	double getX();
	double getY();
	double getZ();
	void setX(double ax);
	void setY(double ay);
	void setZ(double az);
	void dispX(double adisp);
	void pin();
	int isPinned();
};


#endif /* NODE3D_H_ */ 


Node3D.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "Node3D.h"
#include <math.h>

//#define dm(s) ;
#define dm(s) cout<<"--> Node3D::debugmessage: "<<s<<endl;

Node3D::Node3D(double ax, double ay, double az)
	: x(ax), y(ay), z(az) {
}

Node3D::Node3D(double ax, double ay, double az, int apinned)
	: x(ax), y(ay), z(az), pinned(apinned) {
}

double Node3D::getDistance(Node3D & an) {
	return sqrt((x-an.x)*(x-an.x)+(y-an.y)*(y-an.y)+(z-an.z)*(z-an.z));
}

double Node3D::getX() {return x;}
double Node3D::getY() {return y;}
double Node3D::getZ() {return z;}

void Node3D::setX(double ax) {x=ax;}
void Node3D::setY(double ay) {y=ay;}
void Node3D::setZ(double az) {y=az;}

void Node3D::dispX(double adisp) {x+=adisp;}
void Node3D::pin() {
	pinned = PINNED;
}

int Node3D::isPinned() {
	return pinned;
}


Conn.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef CONN_H_
#define CONN_H_

#include "Node3D.h"
#include <iostream>

class Conn {
private:
	Node3D * n1;
	Node3D * n2;
	double initLength;
	static const double E = 210000.0;
	static const double NU = 0.3;

public:
	Conn(Node3D & an1, Node3D & an2);
	Conn(Node3D & an1, Node3D & an2, double ainitLength);
	void connect (Node3D & an1, Node3D & an2);
	void connect (Node3D & an1, Node3D & an2, double ainitLength);
	Node3D & getNode1();
	Node3D & getNode2();
	void setInitLength(double al0);
	double getLength();
	double getDeltaLength();
	void relax();
	double getStrain();
	double getStress();
};


Conn.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "Conn.h"
#include <iostream>

//#define dm(s) ;
#define dm(s) cout<<"--> Conn:debugmessage: "<<s<<endl;

using namespace std;

Conn::Conn(Node3D & an1, Node3D & an2) {
	n1 = NULL;
	n2 = NULL;
	connect(an1,an2);
}


Conn::Conn(Node3D & an1, Node3D & an2, double ainitLength) {
	n1 = NULL;
	n2 = NULL;
	connect(an1,an2,ainitLength);
}


void Conn::connect (Node3D & an1, Node3D & an2, double ainitLength) {
	n1 = &an1;
	n2 = &an2;
	initLength = ainitLength;
}

void Conn::connect (Node3D & an1, Node3D & an2) {
	n1 = &an1;
	n2 = &an2;
	relax();
}

Node3D & Conn::getNode1() {return *n1;}
Node3D & Conn::getNode2() {return *n2;}

void Conn:: setInitLength(double ainitLength) {initLength = ainitLength;}

double Conn::getLength() {return n1->getDistance(*n2);}

double Conn::getDeltaLength() {return getLength()-initLength;}

void Conn::relax() {initLength = getLength();}

double Conn::getStrain() {return (getLength()-initLength)/initLength;}

double Conn::getStress() {return E*getStrain();}



IMSoMechLin.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef IMSOMECHLIN_H_
#define IMSOMECHLIN_H_

#include "Conn.h"
#include <vector>
#include <string>


class IMSoMechLin {
private:
	double edgeLength;
	std::vector<Conn> connectors;
	std::vector<Node3D> nodes;
	Node3D * first,* last;

public:
	IMSoMechLin(int an, double aedgeLength);
	void displace(double adisp);
	void run();
};


#endif /* IMSOMECHLIN_H_ */ 


IMSoMechLin.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "IMSoMechLin.h"
#include <iostream>

//#define dm(s) ;
#define dm(s) //cout<<"--> IMSoMechLin::debugmessage: "<<s<<endl;

using namespace std;

IMSoMechLin::IMSoMechLin(int an, double aedgeLength)
	: edgeLength(aedgeLength) {

	first = NULL;
	last = NULL;

	nodes.clear();
	connectors.clear();

	Conn * myConn = NULL;
	Node3D * myNode = NULL;

	int x=0;	// the x-value of the next/current node
	int i=0;	// counts the nodes being created

	while (i<an) {
		myNode = new Node3D(x,0,0);
		nodes.push_back(*myNode);

		if (i!=0) { // skip first and then connect current with prev.
			if (i>1) cout << "left: " << connectors.at(0).getNode1().getX() << " and right: " << connectors.at(0).getNode2().getX() << endl;
			myConn = new Conn(nodes.at(nodes.size()-2),*myNode);
			connectors.push_back(*myConn);
			cout << "left: " << connectors.at(0).getNode1().getX() << " and right: " << connectors.at(0).getNode2().getX() << endl;
		}



		x += edgeLength;
		i++;
	}


	first = &(nodes.at(0));
	first->pin();
	last = &(nodes.at(nodes.size()-1));

	cout << "[Created Connectors]" << endl;
	for (int j=0; j<connectors.size(); j++) {
		cout << "strain: " << connectors.at(j).getStrain() << endl;
	}

}
First
1
2
		myNode = new Node3D(x,0,0);
		nodes.push_back(*myNode);
is leaking.
Use nodes.push_back( Node3D(x,0,0) ); instead.

I think that the problem is reallocation. When that happens, it will invalidate all your pointers.
You could avoid that by reserve() enough memory (if you do know a limit). Or changing the connection structure (by instance, maintain the index)


Side note:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Node3D {
private:
	double x,y,z;
	bool pinned;
public:
//...
	double getX();
	double getY();
	double getZ();
	void setX(double ax);
	void setY(double ay);
	void setZ(double az);
//...
	int isPinned();
};
You better make your members public instead of wasting time in those accessors
Hey ne555.

Thank you for your reply.

I changed the code to
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
IMSoMechLin::IMSoMechLin(int an, double aedgeLength)
	: edgeLength(aedgeLength) {

	first = NULL;
	last = NULL;

	nodes.clear();
	connectors.clear();

	double x=0.0;	// the x-value of the next/current node
	int i=0;	// counts the nodes being created

	while (i<an) {
		nodes.push_back(Node3D(x,0,0));

		if (i!=0) { // skip first and then connect current with prev.
			connectors.push_back(
				Conn(
						nodes.at(nodes.size()-2),
						nodes.at(nodes.size()-1)
				)
			);
		}

		x += edgeLength;
		i++;
	}


	first = &(nodes.at(0));
	first->pin();
	last = &(nodes.at(nodes.size()-1));

	cout << "[Created Connectors]" << endl;
	for (int j=0; j<connectors.size(); j++) {
		cout << "strain: " << connectors.at(j).getStrain() << endl;
	}

}


but still get weird output - varying between -XYZE-200 and inf (correct would be "0")
I really think that some cout is the problem. If I do the exact same "cout" sequence twice, it sometimes outputs totally different values.
Again, I think that the problem is that the pointers in Conn become dangling pointers.
Because when the vector grows it will move its elements to another memory address (reallocation).

To see it
1
2
for(size_t K=0; K<connectors.size(); ++K)
  std::cerr << connectors[K].n1 << '=' << &node[K] << ' ';
and you will note that the address are different.

Or if you prefer
1
2
for(size_t K=0; K+1<connectors.size(); ++K)
  std::cerr << connectors[K].n2 << '=' << connectors[K+1].n1 << '\t';
Topic archived. No new replies allowed.