将地址存储到向量中的堆栈分配对象

Posted

技术标签:

【中文标题】将地址存储到向量中的堆栈分配对象【英文标题】:Storing adress to stack allocated object in vector 【发布时间】:2016-03-24 10:51:59 【问题描述】:

我在为向量中的堆栈分配对象存储指向地址的指针时遇到问题。不知何故,指针似乎以我不理解的方式相互覆盖。

在我的主文件中,我想从文件中读取,创建节点(分配堆栈)并将它们放入向量中。后来我继续从文件中读取以在节点之间创建连接(边缘),从而堆栈分配边缘对象并尝试将地址存储到相应的节点中(节点包含一个向量)。输入文件的格式为 index_1 a, index_2, b, capacity c,这意味着要创建从 a 到 b 的 Edge,反之亦然,容量为 c。

每次我将 Edge 添加到节点 (vector::push_back()) 时,节点中的整个向量都会设置为相同的指针(而不是像预期的那样只是附加另一个指针)。将 3 条边添加到同一节点后的示例输出:

#0 named: ORIGINS connected to: 
#1 named: 2, capacity: -1, flow: 0

#0 named: ORIGINS connected to: 
#17 named: 3W, capacity: -1, flow: 0
#17 named: 3W, capacity: -1, flow: 0

#0 named: ORIGINS connected to: 
#16 named: 3E, capacity: -1, flow: 0
#16 named: 3E, capacity: -1, flow: 0
#16 named: 3E, capacity: -1, flow: 0

如果我的代码中有任何测试或打印,请原谅:

主要:

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <string>
#include <fstream>
#include <algorithm>
#include <map>
#include <sstream>
#include "Edge.h"
#include "Node.h"
#include <memory>

using namespace std;

ostream& operator<<(ostream& os, const Node& obj) 
    os << "#" << obj.index << " named: " << obj.name << " connected to: " << endl;
    for (size_t i = 0; i < obj.edges.size(); ++i) 
        Edge* e = obj.edges[i];
        os << "#" << e->getEndNode()->getIndex() << " named: " << e->getEndNode()->getName() << ", capacity: " << e->getCapacity() << ", flow: " << e->getFlow() << endl;
    
    return os;


int main() 
    string fileName = "rail.txt";

    //open file
    ifstream infile(fileName.c_str());

    //initialize variables
    string line;
    vector<Node> graph;

    int n;
    getline(infile, line);
    n = atoi(line.c_str());
    //read n nodes
    for (int i = 0; i < n; ++i) 
        if (getline(infile, line)) 
            Node node(line, i);
            graph.push_back(node);
         else 
            cout << "Error in parsing nodes" << endl;
            return 1;
        
    

    int m;
    getline(infile, line);
    m = atoi(line.c_str());
    //read m edges
    for (int i = 0; i < m; ++i) 
        if (getline(infile, line)) 
            istringstream iss(line);
            int a, b, c;

            iss >> a >> b >> c;
            Edge e1(&graph[b], c, 0);
            Edge e2(&graph[a], c, 0);
            graph[a].addEdge(&e1);
            graph[b].addEdge(&e2);
            cout << graph[a] << endl;
         else 
            cout << "Error in parsing edges" << endl;
            return 1;
        
    

    /*for (auto e : graph[0].getEdges()) 
        cout << e->getEndNode()->getName() << endl;
    */


    return 0;

Edge.cpp:

#include "Edge.h"

Edge::Edge() : endNode(nullptr), capacity(0), flow(0) ;
Edge::Edge(Node* n, int c, int f) : endNode(n), capacity(c), flow(f) ;
Edge::Edge(const Edge& other) 
    endNode = other.endNode;
    capacity = other.capacity;
    flow = other.flow;
;

bool Edge::pushFlow(int f) 
    if (flow + f <= capacity) 
        flow += f;
        return true;
     else 
        return false;
    


bool Edge::popFlow(int f) 
    if (flow - f >= 0) 
        flow -= f;
        return true;
     else 
        return false;
    


Node* Edge::getEndNode() 
    return endNode;


int Edge::getCapacity() 
    return capacity;


int Edge::getFlow() 
    return flow;

Node.cpp:

#include "Node.h"
#include <iostream>
Node::Node() : name(""), index(-1) ;
Node::Node(std::string n, int i) : name(n), index(i) ;
Node::Node(const Node& other) : name(other.name), index(other.index), edges(other.edges) ;

void Node::addEdge(Edge* e) 
    edges.push_back(e);


std::vector<Edge*> Node::getEdges() 
    return edges;


Node& Node::operator=(const Node& rhs) 
    if (this == &rhs) return *this;
    name = rhs.name;
    index = rhs.index;
    edges = rhs.edges;
    return *this;


std::string Node::getName() 
    return name;


int Node::getIndex() 
    return index;

感谢您的任何帮助或指点(呵呵)!

【问题讨论】:

堆栈分配的实例一旦超出范围就会被销毁,因此在该范围之外使用它们的地址肯定不是一个好主意。 在以后的问题中,请务必将您的代码简化为最小但完整的示例,供读者试用。 假设您梦想中的跑车停在榆树街 1428 号。第二天,你遇到了一个好朋友,你说“去榆树街 1428 号,看看我梦寐以求的车”。他回来说:“你为什么梦想一辆垃圾车?你需要帮助”。你明白这是怎么发生的吗? @molbdnilo 你的评论让我想起了一个朋友,他曾经用附近的一辆豪车标记他的停车场......他通常会花几个小时寻找它...... 【参考方案1】:

一旦执行离开作用域,就会在其中声明一个非static 变量,该变量将不复存在,指向它的指针变为悬空指针

悬空指针无效。即使只是检查该值也可能导致硬件陷阱。因此,任何使用它都是未定义的行为。

这就是你所拥有的,因为你会做这样的事情

graph[a].addEdge(&e1);

在循环中,e1 是在循环体中声明的变量。

【讨论】:

我明白了。所以你必须堆分配一切? @Pkaff 推送你的节点的副本,这样就可以了。 @Pkaff 更改您的向量以保持 Edge 而不是指向 Edge 的指针。如果需要指针,则必须动态分配它们。

以上是关于将地址存储到向量中的堆栈分配对象的主要内容,如果未能解决你的问题,请参考以下文章

对象向量是不是在 C++ 中的堆或堆栈上分配?

寻找类似 C++ STL 的向量类但使用堆栈存储

PHP对象在内存堆栈中的分配

PHP对象在内存堆栈中的分配

js中的简单数据类型和复杂数据类型的存储

我自己的堆栈类中的 C++ 奇怪行为