将C ++ new运算符与函数一起使用的明智方法是什么?

| 这是一个很长的时间。我有一个从磁盘加载一些图像数据的功能。我已经尝试了三种不同的方法,其中一种不起作用,我想知道最聪明的方法是什么。 方法1: 我曾经进行过设置,以使加载的数据成为函数的参数,这似乎需要在函数外部为其分配空间,然后将指针传递给已分配的空间。这需要提前知道图像的大小,因此必须进行辅助功能才能首先获得图像的宽度和高度。以下是一个示例。 优点:在调用代码中更明确地表明正在分配内存,因此应将其删除。 缺点:需要提前知道图像大小。
// Data allocated outside the image, allocated space passed to function. This works.
// Notice that width & height are passed to the function. 
size=(*width)*(*height);
image  = new unsigned char[size];

void read_pgm(unsigned char *image, char *file_name, int width, int height){

    // Code to read sizeof(char)*width*height bytes of data from the file into image

}
方法2: 我认为让函数分配自己的数据会很好,所以我不需要传递大小。如果我试图在函数中为其分配空间,则函数结束后似乎丢失了空间。在以下情况下,函数
read_pgm
运行良好,但是如果我随后尝试将该数据写入另一个文件,则代码将崩溃。 优点:不需要提前知道图像大小,无需在调用代码中分配数据。 缺点:不起作用。此外,如果这样做的话,如果我不清除函数外部的图像,是否会在循环中反复调用它导致内存泄漏?
// Data allocated inside the image for a pointer passed to the function. This doesn\'t work.
void read_pgm(unsigned char *image, char *file_name, int *width, int *height){

    size=(*width)*(*height);
    image  = new unsigned char[size];

    // Code to read the data from the file into image

}
方法3: 此处,数据再次在函数中分配,但作为返回的项目移回。这可以工作,即我可以将数据写到另一个图像上。我不明白为什么这行得通,而方法2却行不通。 优点:与方法2相同。 缺点:与方法2相同,但当前可以使用。
// Data allocated in the function, and returned. This works.
unsigned char* read_pgm(char *file_name, int *width, int *height){

    // Allocate data for the image
    size=(*width)*(*height);
    image  = new unsigned char[size];

    // Code to read the data from the file into image

    return image; // Return pointer to the data
}
因此,我的问题是: 在这种情况下,将函数设置为自己分配空间是否更聪明,因此调用代码不需要提供图像大小?还是在函数外部进行分配是更明智的选择,以提醒需要在某个时刻在图像上调用delete。还是我认为需要这样做是错误的?似乎在循环中调用方法2或方法3会导致内存泄漏。 为什么方法2不起作用? 谢谢。     
已邀请:
        问题2的答案 为了使其正常工作,您必须将引用传递给指针
unsigned char * & image
否则,您将分配内存,并且传递的指针的COPY指向该内存。原始指针对象不变。 回答问题1 听说过智能指针吗? 智能指针可用于自己全部操纵内存。如果由于某种无法解释的原因(例如伪优化)而不想使用智能指针,那么我认为您自己描述了所有方法的优缺点-总是存在权衡的。由您决定     
        如果您想知道聪明的方法,那么答案必须是“以上皆非”。聪明的方法?使用向量。那就是它的目的。因为直接使用
new
很烂。管理您自己的内存范围很糟糕。我们为此提供课程。 string6ѭ呢?至少使它成为
const char*
const std::string&
更好。我还必须问-您要尝试读取哪种图像格式,而不以文件格式存储图像的宽度和高度?在我看来,最好从文件中读取该文件。
std::vector<unsigned int> void ReadImage(const std::string& filename, int width, int height) {
    std::vector<unsigned int> imageData(width * height);
    // Read here from filestream
}

std::vector<unsigned int> imageData = ReadImage(\"ohai.png\", 1000, 600);
您需要了解-const正确性,RAII和标准库。     
        方法2不起作用,因为您要按值传递指针,并在本地覆盖该值,因此函数外部的指针值不会更改。您可以通过按引用传递它或将指针传递给指针来解决此问题。 至于另一个问题:这实际上只是清楚地记录谁有责任删除分配的数据。 (顺便说一句:是的,您应该取消分配,否则将泄漏)。在许多API中,您会在文档中看到:\“调用者有责任删除此数据\”或\“调用此其他函数删除已分配的数据\”。 消除此类所有权问题的一种好方法是使用智能指针(如Armen所建议的)。     
        您目前所做的每件事都会导致内存泄漏,因为您绝不会“ѭ”十分钱。 首先,是的,使尺寸可变。其次,返回指向新分配的堆存储的指针并记住在调用方中将其删除,或者返回一个智能容器对象。
std::vector<unsigned char>
会做得很好:
std::vector<unsigned char> get_image(const std::string & filename, size_t & width, size_t & height)
{
  // determine width and height

  /* ... */

  std::vector<unsigned char> result(width * height, 0);

  // read into &result[0], vector guarantees contiguous storage

  return result;
}
    
考虑将与读取和“处理”数据有关的所有功能封装在一个类中。 它应该将文件路径作为构造函数中的std :: string。 然后可以在一个单独的函数中创建文件句柄,分配内存和读取(类似于
Init
)。这样,您便可以在知道文件路径时创建对象,但稍后在实际需要时执行耗时的部分(读取部分)。 您可以向外部用户公开任何必要的信息(例如身高或宽度)。 类析构函数将负责关闭文件句柄(如果需要,可以更早完成)并取消分配数据。 您可以在类中使用new和delete,或者更好的是,在类中使用智能指针,而不仅仅是图像数据部分。您还可以“在堆栈上”使用它,并在超出范围时自动调用其析构函数。     
        \“ 2。为什么方法2不起作用?\” 因为您要通过副本而不是引用传递指针。您传入一个指针,然后通过
new
调用立即重新初始化该指针指向的位置。达到函数的作用域后,局部变量
image
的寿命以及所有可爱的新存储都将到达。 您真正想做的(在这种情况下)是传递对指针的引用或指向指针的指针,以便您可以更改传递的参数的值(在本例中为指针),并使更改可见在功能范围之外。
void read_pgm(unsigned char **image, char *file_name, int *width, int *height)
{      
    size=(*width)*(*height);     
    (*image)  = new unsigned char[size];      

    // Code to read the data from the file into image  
} 
    
        实际上,C ++ FAQBook中有一个非常出色的部分,针对这些问题。 正如您所说,最大的问题是确保以不会泄漏的方式分配内存。 C ++有很多方便的工具可以做到这一点,最明显的是
new
delete
。 最简单的方法是在超出范围的情况下用
new
分配存储空间。所以...
 {
     MyData *md = new MyData(args);

     doSomething(md);

 }
现在,当md超出范围时,它将自动调用dtor。现在,这个技巧几乎可以在任何地方使用。 使用方法2,您按原样写对了,它会泄漏内存;下次您执行“ 5”时,对上一次的引用将丢失,但不会最终确定或销毁。 一种解决方案是在其他地方显式调用dtor,即将其删除。 我怀疑它不起作用的原因是
image
是一个指针,这是new想要返回的指针。但是由于C ++会执行按值调用的指针,因此您将该地址放入堆栈的本地内存中,并且该地址消失了。 您可能想要一个23英镑,甚至更好的参考。 第三种解决方案是C ++确实具有指针类型来帮助免费商店管理。 FAQbook在这里描述了如何实现引用计数指针。     

要回复问题请先登录注册