指针的C++容器

指针的C++容器,c++,pointers,containers,heap-memory,stack-memory,C++,Pointers,Containers,Heap Memory,Stack Memory,我今天一直在思考一个问题,很难在谷歌上找到答案 我试图理解STL容器在处理指向堆上和堆栈上分配的对象的指针时的行为 所以,从对象开始,没有指针。。。想象一下我有 std::vector<int> myVec; while(true) { int myInt = 5; myVec.push_back(myInt); myVec.pop_back(); } 我的理解是pop_back方法将确保向量中包含的整数被删除,而不仅仅是从容器中删除。所以,如果这个程序运行

我今天一直在思考一个问题,很难在谷歌上找到答案

我试图理解STL容器在处理指向堆上和堆栈上分配的对象的指针时的行为

所以,从对象开始,没有指针。。。想象一下我有

std::vector<int> myVec;
while(true)
{
    int myInt = 5;
    myVec.push_back(myInt);
    myVec.pop_back();
}
我的理解是pop_back方法将确保向量中包含的整数被删除,而不仅仅是从容器中删除。所以,如果这个程序运行并进行了10亿次迭代,我就不会期望内存泄漏。我插入的所有内容都将被删除。内存检查会显示这种行为

现在考虑我使用堆的指针指向堆上的对象…

std::vector<int*> myVec;
while(true)
{
    int * myIntP = new int(5);
    myVec.push_back(myIntP);
    myVec.pop_back();
}
在这种情况下,每次调用pop_back时只应删除指针本身,并且底层对象保持未删除状态,从而导致内存泄漏。因此,经过十亿次迭代之后,我有相当多的内存被使用,即使我的向量中没有条目

现在,如果我有一个指向堆栈上对象的指针向量

std::vector<int*> myVec;
while(true)
{
    int myInt = 5;
    int * myIntP = &myInt;
    myVec.push_back(myIntP);
    myVec.pop_back();
}
这里的指针指向堆栈对象。他们的内存是否在回拨时释放?内存检查表明,这种行为没有内存泄漏。使用的内存量很小,这表明它的行为类似于堆栈上的对象。然而,我并不期望这样,因为如果指针是从另一个函数传入我的,那么它将被传递到堆栈变量,即

void myFunc(int * myIntP)
{
    std::vector<int*> myVec;
    myVec.push_back(myIntP);
    myVec.pop_back();
}
int main()
{
    int myInt = 5;                                                                                                                      
    int * myIntP = &myInt;
    myFunc(myIntP);
    std::cout << (*myIntP) << std::endl;
    return 0;
}
然后允许向量释放内存,将使myIntP指向删除的数据。那么这肯定是不对的

有人能解释一下吗

此外,是否有指向堆栈上变量的指针的名称,即未使用new初始化

谢谢


Joey

如果在堆栈上创建一个指向变量的指针,那么当变量超出范围时,无论指针是什么,该变量都将被销毁。只要不调用delete,销毁指针对变量没有影响


所以,如果您以前停止使用指针,没问题,如果您将其存储更长时间,问题


如果您计划在动态分配的变量上使用指针,您应该研究智能指针。

我认为您需要深入了解范围变量的有效性 例如:

 {
  int myVar;//Construct myVar on the stack
 }//At this point, myVar is deleted with the stack
在上一个示例中,您在main的开头声明myInt,而不在myFunc中对值执行任何操作

不丢失myInt数据是正常的。返回0后将被擦除

这里的指针指向堆栈对象。他们的内存是否在回拨时释放

不,他们不是。它们在超出作用域时被释放,这发生在}。在}之后,内存不再用于此变量,堆栈帧弹出并将重新使用!因此,如果在按下指针后没有立即弹出指针,那么当变量超出范围时,向量将包含一个悬空指针

while(true)
{
    int myInt = 5;
    int * myIntP = &myInt;
    myVec.push_back(myIntP);
    myVec.pop_back();
}
实际上这里只有一个int,值为5的myInt。循环将重复使用相同的循环。将指向该整数的指针推入向量,然后将其移除。没有别的事情发生。没有内存泄漏,因为您没有分配新的int


STD容器对指针的作用与对32/64位整数的作用相同。就他们而言,指针只是另一个数字。因此,如果您在容器中插入指针,则您有责任删除它。

因此,让我们看一下您的每个示例:

std::vector<int> myVec;
while(true)
{
    int myInt = 5;
    myVec.push_back(myInt);
    myVec.pop_back();
}

请注意,即使这样做,容器也会复制该值。因此,MyIt仍然不受影响。

你混淆和合并破坏和删除-它们不是同一事物,而是C++中的两个不同概念。 删除只能发生在指针上-如果您试图删除非指针,您将得到编译时错误。删除首先销毁指向的对象,然后将其内存返回堆

另一方面,破坏可以发生在任何东西上,但主要只对类感兴趣,它在类中调用析构函数。对于任何没有析构函数的类型,如int或任何原始指针类型,析构函数都不会执行任何操作。虽然你可以手动销毁一个对象,但你几乎从来没有这样做过——当其他事情发生时,它会自动为你销毁。例如,当局部变量超出范围时,它将被销毁

那么在上面的代码中,会发生什么?这里有一个本地std::vector,当它超出范围时会被销毁。它的析构函数将删除它内部分配的任何内容,并销毁向量的所有元素。但是,它不会删除向量的任何元素。当你有了向量,这就是全部,因为没有分配其他任何东西,但是当你有了向量,如果那些指针被分配了,它们就会泄漏。如果它们指向局部而没有被分配,那么就没有什么可泄漏的。

向量只存储你的结构。如果您的结构是指针,那么向量不会检查
至少,它是有效的,并且不会释放它指向的内存。当您动态分配时,您可能希望使用智能指针,其析构函数释放分配的内存。尽管如此,向量不知道或不关心指针指向什么。当你从向量中移除一个对象时,它会删除指针占用的内存,但不会删除它指向的对象,不管该对象是在堆栈上还是在堆上。好的,但是如果我希望这个while循环永远执行,堆栈对象永远不会超出范围。然而,我仍然想从记忆中删除它们。我自己怎么处理呢?堆栈框架将超出范围。当我说,它超出了}的范围,这不仅仅意味着while循环结束,而是在每次迭代之后。啊,好的。这就是我不明白的。那么,在指针弹出后,我让对象占用内存的唯一原因是,如果我用new声明指针,而不是调用delete?是的,没错。Stackspace局部变量,本质上,当创建它们的作用域结束时,没有使用new创建的所有对象都会自动释放。因此,如果在[对象超出作用域]之前停止使用指针,没有问题,如果您再存储它,问题。。。我理解这一点,但如果我希望我的while循环无限期地执行,但又不想在内存中加载冗余对象,也就是说,当我回拨pop_时,我知道我已经处理完它们了。我如何确保这一点?要么不要使用指针,要么使用智能指针确保在指针被销毁时删除分配的内存。
std::vector<int*> myVec;
while(true)
{
    int * myIntP = new int(5);
    myVec.push_back(myIntP);
    myVec.pop_back();
}
std::vector<int*> myVec;
while(true)
{
    int myInt = 5;
    int * myIntP = &myInt;
    myVec.push_back(myIntP);
    myVec.pop_back();
}
void myFunc(int * myIntP)
{
    std::vector<int*> myVec;
    myVec.push_back(myIntP);
    myVec.pop_back();
}
int main()
{
    int myInt = 5;                                                                                                                      
    int * myIntP = &myInt;
    myFunc(myIntP);
    std::cout << (*myIntP) << std::endl;
    return 0;
}
myVec.push_back(*myIntP);