离开循环时的矢量数据丢失

Posted

技术标签:

【中文标题】离开循环时的矢量数据丢失【英文标题】:Vector Data Loss When Leaving A Loop 【发布时间】:2016-09-12 14:18:14 【问题描述】:

我不认为自己是编程新手,但我在六个月的大部分时间里一直在努力理解向量。

我尝试在“生产”代码中使用向量,但它似乎从来没有达到我的预期。这个例子是我遇到的许多问题之一,正如标题中所述,Vectors 在离开 while 循环后似乎神秘地丢失了数据。这可能归结为我只是使用错误的向量,但我想我的过程至少有点合理。正如您将注意到的,这是一个对象向量,这也可能是该问题的关键。

在我制作的这个例子中,一个带有随机字符的 char 指针被添加到向量中,正好十次。每次都会擦除 char 指针的内容并添加新内容以确保数据的唯一性。离开循环并开始另一个循环以打印出向量的内容后,刚刚添加到向量中的数据不再存在。为什么?

此外,从我看到的示例来看,向量的初始化是非标准的,但似乎是让向量在不崩溃的情况下工作的唯一方法。

抱歉我的格式不好,代码块中的样式与我的代码格式不完全一样(括号间距有点搞砸了)提前谢谢!

#include <stdio.h>
#include <vector>
#include <stdlib.h>



int main( int argc, char * argv[ ] ) 

    std::vector<char *> avector( 0 );
    avector.reserve( 400 );
    int counter = 0;
    char * place;
    bool ok;

    Back:
    if( counter == 10 ) 
        counter = 0;
        while( counter != 10 )
            printf( "Element %d: %s\n", counter,  avector.at( counter ) );
            ++counter
        
        ok = false;
    
    while( counter != 10 ) 
        ok = true;
        place = (char *)malloc( 10 * sizeof( char ) );
        *place = (char)( ( rand( ) % 26 ) + 65 );
        printf("Pre-placement, element %d: %s\n", counter, place );
        avector.push_back( place );
        printf("Post-placement element %d: %s\n", counter, avector.at( counter ) );
        free( place );
        ++counter;

    
    if( ok == true ) 
        goto Back;
    


    exit( 0 );

【问题讨论】:

这是一个对象向量’ 呃,不。它是char* 的向量。 向量不会“丢失”数据。你删除它。您使用“malloc”创建一个内存块,然后将其地址推送到向量中(注意。您不复制内存,只是将地址存储在那里),然后您删除内存与free。在我看来,你应该更多地开始学习指针而不是向量(或者在 c++ 中停止使用 malloc/free。这不是 C) goto Back; 好的。我不想刻薄。我相信你在编写这段代码时是出于好意。但是为了图灵的爱,为什么你会写goto声明???? 您的代码/设计的用例(现实生活中的问题)是什么?您真的需要实施这种方法吗? @Xirema 不应该是“为了 Dijkstra 的爱”吗? 【参考方案1】:

place = (char *)malloc( 10 * sizeof( char ) ); 您正在使用 malloc 分配数据

avector.push_back( place ); 你把它推到向量上

free( place ); 然后,您将其删除。因此,指针仍在向量中,但内存地址不再属于您。

另外,您使用的是 C++,而不是 C,所以不要使用 printf、goto、malloc 和 free。 并尽量不要使用 new 和 delete,而是使用智能指针 (C++11)

【讨论】:

我以为你推回去的时候内容被复制到了vector中。谢谢你澄清这一点。我也会研究智能指针。【参考方案2】:

您的代码中的主要错误是您添加了指向向量的指针,但随后使您存储在其中的指针无效。

place = (char *)malloc( 10 * sizeof( char ) );
avector.push_back( place );
free( place );   // <<--- BUG; you destroyed what's pointed to by place

错误在于placeavector 中添加place 的位置(比如avector[avector.size() - 1])都指向同一个内存位置,所以freeing place 是与在循环的给定迭代中 freeing avector[avector.size() - 1] 相同。

您基本上已经从自己的脚下拉了地毯。

我认为一个更简单的例子可以帮助你看得更清楚。这是您的代码的重构版本,使用适当的 C++ 而不是 C++ 和 C 的混合:

#include <iostream>
#include <vector>

using namespace std;

int main( int argc, char * argv[ ] ) 
    vector<char *> my_char_pointers;

    cout << "Filling up vector ..." << endl;
    for(int i = 0; i < 5; ++i) 
        cout << "Adding address of " << char(65 + i) << " to vector ..." << endl;
        my_char_pointers.push_back(new char(65 + i));
    

    cout << "Printing vector ..." << endl;
    for(int i = 0; i < my_char_pointers.size(); ++i)
        cout << my_char_pointers.at(i) << endl;

    cout << "Deleting char pointer vector elements ..." << endl;
    for(int i = 0; i < my_char_pointers.size(); ++i)
        delete my_char_pointers[i];

    cout << "Printing vector of now-INVALID pointers ..." << endl;
    for(int i = 0; i < my_char_pointers.size(); ++i)
        cout << my_char_pointers.at(i) << endl;

    cout << "Removing the now invalid pointers from vector ..." << endl;
    my_char_pointers.clear();

    return 0;

在我的 Linux PC 上运行它,你会得到以下输出:

$ g++ -o test test.cpp
$ ./test 
Filling up vector ...
Adding address of A to vector ...
Adding address of B to vector ...
Adding address of C to vector ...
Adding address of D to vector ...
Adding address of E to vector ...
Printing vector ...
A
B
C
D
E
Deleting char pointer vector elements ...
Printing vector of now-INVALID pointers ...

 ��
`��
@��
���
Removing the now invalid pointers from vector ...

您的版本和我的版本之间需要注意的一些差异,包括错误修复和其他细节:

    我创建,但不 deletevector 在同一循环内输入(这是修复); 您的代码难以跟踪,使错误更难以捕获/调试; 它使用newdelete,这是在C++ 中分配/释放内存的正确方法(malloc 和朋友们都支持C) 它使用 &lt;iostream&gt; 中的 cout,这是在 C++ 中打印输出的正确方法(printf 用于 C) 它使用结构合理的代码,并且依赖于goto[1],这会导致意大利面条式代码; 而且我的代码更容易理解/理解,使任何错误更容易找到/修复

如果您真的不想成为“编程新手”,则需要处理代码结构、简化逻辑和其他细节。

还请注意,您实际上并没有“对象”的vector;你有一个指向chars的向量。名为my_char_pointersvector 是一个对象,但其内容是原始 类型。 (是的,术语确实有所作为。)

[1] 为什么你会在 Dijkstra 的名字上使用goto 语句?它们会给您自己以及将来不可避免地需要阅读您的代码的人带来很多麻烦。

【讨论】:

以上是关于离开循环时的矢量数据丢失的主要内容,如果未能解决你的问题,请参考以下文章

ArcGIS风暴ArcGIS矢量数据分层设色后导出或裁剪后颜色分类丢失完美解决办法

ArcGIS风暴ArcGIS矢量数据分层设色后导出或裁剪后颜色分类丢失完美解决办法

JavaScript Javascript警告用户如果他们离开此页面他们将丢失数据

R ggplot2绘制具有不等长度矢量的循环

使用 BehaviorSubject 重新加载时的角度数据丢失

在反应中丢失页面刷新时的组件数据