PDA

View Full Version : [C++] Reference a oggetto di una classe sembra non essere valorizzato


-Ivan-
13-07-2013, 10:48
Sto implementando questa classe:


typedef Graph<GraphNode, GraphEdge> GraphType;

template <class graph_type, class node_type, class edge_type>
class DijkstraSearch
{
public:

typedef node_type Node;
typedef edge_type Edge;
typedef graph_type Graph;

private:

//the graph the algorithm is runned on
const Graph& graph;

//stores the closest node to compute in the next step
int nextClosestNode;

//Search Path Tree built by the algorithm
std::vector<const Edge*> spt;

//cost to reach each node from the source (the index inside the vector is the index of the node)
std::vector<double> costToThisNode;

//vector containing parent edges leading to the node connected to the spt but not added to the spt yet
std::vector<const Edge*> searchFrontier;

//source and target for the search
int source;
int target;

void Search();

public:

DijkstraSearch( const Graph& p_Graph,
int p_Source,
int p_Target = -1)
:
graph(p_Graph),
spt(p_Graph.NumNodes()), //init with the number of nodes in the graph
searchFrontier(p_Graph.NumNodes()), //init with the number of nodes in the graph
costToThisNode(p_Graph.NumNodes()), //init with the number of nodes in the graph
source(p_Source),
target(p_Target)
{
//std::cout<<"p_Source: "<<p_Source<<std::endl;
//std::cout<<"p_Target: "<<p_Target<<std::endl;
//p_Graph.PrintGraph();
std::cout<<"searchfrontier size: "<<p_Graph.NumNodes()<<std::endl;
//std::cout<<"costToThisNode size: "<<costToThisNode.size()<<std::endl;
Search(); //run the search when instantiated
}

std::list<int> GetPathToTarget()const;

};


Ma dentro al costruttore p_Graph sembra non essere valorizzato, infatti poi NumNodes() mi restituisce 0 ed i vari vettori non sono inizializzati e fanno crashare il programma.
Il main è questo:


int _tmain(int argc, _TCHAR* argv[])
{
//istantiate a graph
GraphType *graph = new GraphType(true);

//graph->PopulateRandom(5, 8);

graph->CreateTestGraph();
//graph->PrintGraph();

//test dijkstra algorithm
DijkstraSearch<GraphType, GraphNode, GraphEdge> *dijkstraSearch = new DijkstraSearch<GraphType, GraphNode, GraphEdge>( graph, 0, 2);
//print the resulting SPT
dijkstraSearch->GetPathToTarget();

delete graph;
system("pause");

return 0;
}


Il grafo che creo nel main è costruito bene, se decommmento la riga che fa PrintGraph mi stampa esattamente il grafo di test che voglio. E' un errore sulla variabile di tipo reference? Ho letto che occorre che siano inizializzate al momento della dichiarazione ma poi ho visto anche che lo si può fare nel costruttore (spero di non sbagliarmi).

-Ivan-
13-07-2013, 13:57
Problema risolto.
La chiamata deve essere:


DijkstraSearch<GraphType, GraphNode, GraphEdge> *dijkstraSearch = new DijkstraSearch<GraphType, GraphNode, GraphEdge>( *graph, 0, 2);


graph deve essere passato con il dereference.
(Per punirmi sto per guardare un video di 48 minuti solo sui puntatori).

vendettaaaaa
13-07-2013, 16:21
Come l'altra volta...ma evitarli, questi puntatori, no?? :D

-Ivan-
13-07-2013, 18:53
Mi sono fatto il lavaggio del cervello. Spero di ricordarmene per le prossime volte :mc: .
Mi resta da approfondire i reference e come funzionano i template dal punto di vista dei puntatori.

vendettaaaaa
13-07-2013, 19:16
come funzionano i template dal punto di vista dei puntatori.
Che intendi?

-Ivan-
13-07-2013, 20:20
Ah è sempre riguardo la stessa cosa, non ho ancora digerito bene alcune cose e devo approfondire la teoria che c'è dietro.
Per esempio qui:


template <class node_type, class edge_type>
int Graph<node_type, edge_type>::AddNode(node_type node)
{
//trying to add a node that was already in the graph
if ( node.Index() < (int)nodes.size())
{
......
....
...
}


la chiamata è questa:

GraphNode *node = new GraphNode(i);
AddNode(*node);


node è un puntatore ad un oggetto della mia classe, lo passo con il dereference perchè, immagino, voglio passare il valore di node alla funzione.
Poi la funzione lo usa senza * perchè ha il valore del nodo e non l'indirizzo di memoria (tant'è che come sintassi posso usare il punto '.' invece del '->' che risolve il puntatore come si farebbe con '(*node).' ).
Dunque devo desumere che node lì è passato per copia? Se io modifico node in realtà sto modificando solo il node che è nello scope della funzione?
Probabilmente sì (ma anche probabilmente no visto che non sono molto convinto di quello che ho detto) ma devo studiarmi un po' la teoria.

Lo stesso per gli iterator che mi pare vengano sempre considerati come puntatori ma nelle guide che ho seguito faceva solo un breve accenno a questa cosa e vorrei almeno rileggerla.

vendettaaaaa
13-07-2013, 21:35
Ah è sempre riguardo la stessa cosa, non ho ancora digerito bene alcune cose e devo approfondire la teoria che c'è dietro.
Per esempio qui:


template <class node_type, class edge_type>
int Graph<node_type, edge_type>::AddNode(node_type node)
{
//trying to add a node that was already in the graph
if ( node.Index() < (int)nodes.size())
{
......
....
...
}


la chiamata è questa:

GraphNode *node = new GraphNode(i);
AddNode(*node);


node è un puntatore ad un oggetto della mia classe, lo passo con il dereference perchè, immagino, voglio passare il valore di node alla funzione.
Poi la funzione lo usa senza * perchè ha il valore del nodo e non l'indirizzo di memoria (tant'è che come sintassi posso usare il punto '.' invece del '->' che risolve il puntatore come si farebbe con '(*node).' ).
Dunque devo desumere che node lì è passato per copia? Se io modifico node in realtà sto modificando solo il node che è nello scope della funzione?
Probabilmente sì (ma anche probabilmente no visto che non sono molto convinto di quello che ho detto) ma devo studiarmi un po' la teoria.

Lo stesso per gli iterator che mi pare vengano sempre considerati come puntatori ma nelle guide che ho seguito faceva solo un breve accenno a questa cosa e vorrei almeno rileggerla.
Sì, viene passato per copia perchè è la firma della funzione ricevente a deciderlo, cioè la lista parametri: la funzione riceve un node_type, quindi il nodo viene copiato. Se vuoi modificarlo, AddNode deve ricevere un node_type&.
E' logico che sia la funzione a decidere se poter modificare un oggetto passato come parametro, perchè se così non fosse una stessa funzione potrebbe essere usata con effetti diversi scegliendo da fuori se passare un reference o una copia (a parte che non c'è la sintassi per farlo, parlo giusto in linea teorica).

marco.r
17-07-2013, 14:19
Come l'altra volta...ma evitarli, questi puntatori, no?? :D

L'uso dei reference non preclude l'uso dei puntatori.
Ci sono ottimi motivi per usare sia gli uni che gli altri.

vendettaaaaa
17-07-2013, 14:27
L'uso dei reference non preclude l'uso dei puntatori.
Ci sono ottimi motivi per usare sia gli uni che gli altri.
Uno dei pochi motivi per usare i puntatori nudi è come reference a oggetti già esistenti, quando viene scomodo dover per forza inizializzare una reference (o se non puoi usarle, come in un vector<T&> che non puoi fare, devi usare vector<T*>). Altrimenti meglio usare una delle nuove classi, o oggetti veri e propri definendo dei move constructor.