How to avoid error "warning: ISO C ++ forbids variable length array 'fileName' [-Wvla]" in C ++ 11

1

I have the following piece of code that aims to create a buffer for the file name that will be created based on some information provided in the instantiation of the class:

char fileName[size];
memset(fileName,'\n',size);
sprintf(fileName, "%s/%s%s-%05u.%s", filePath.c_str(), filePrefix.c_str(), date, this->image_counter++, fileExtension.c_str());
cv::imwrite(fileName, frame);
delete[] fileName;

When compiling this code I am getting the following message:

ObjectTracker.cpp: In member function ‘void ObjectTracker::PersistImage(cv::Mat&)’:
ObjectTracker.cpp:80:20: warning: ISO C++ forbids variable length array ‘fileName’ [-Wvla]
  char fileName[size];
                    ^
ObjectTracker.cpp:85:11: warning: deleting array ‘fileName’
  delete[] fileName;
           ^

What would be the most elegant and technical way to write such a code and avoid this error?

I'm using C ++ 11;

    
asked by anonymous 11.10.2016 / 10:09

2 answers

2

Two errors:

  • C language allows the creation of arrays on the stack of variable length, but C ++ does not. In C ++ the size of the arrays allocated in the stack must be known at compile time.
  • You are giving delete to free memory from an array allocated on the stack. This is neither permitted nor necessary. Objects created on the stack are destroyed automatically at the end of the scope that declared them.
  • If the array has a fixed size, set at compile time, it is not necessary to give delete[] in it.

    If your size is variable then you will need to do dynamic allocation. Some options:

    Manual management:

    char *fileName = new char[size];
    memset(fileName,'\n',size);
    sprintf(fileName, "%s/%s%s-%05u.%s", filePath.c_str(), filePrefix.c_str(), date, this->image_counter++, fileExtension.c_str());
    cv::imwrite(fileName, frame);
    delete[] fileName;
    

    Automatic management with unique_ptr :

    std::unique_ptr<char[]> fileName(new char[size]);
    memset(fileName.get(),'\n',size);
    sprintf(fileName.get(), "%s/%s%s-%05u.%s", filePath.c_str(), filePrefix.c_str(), date, this->image_counter++, fileExtension.c_str());
    cv::imwrite(fileName.get(), frame);
    //Não é necessário dar delete, quando o unique_ptr sair de escopo ele liberará a memória
    

    The two tests generate exactly the same assembly, as can be seen here in a simplified example: link . There is no loss of performance by using std::unique_ptr .

    Another option is with std::vector :

    std::vector<char> fileName(size, '\n');//Cria um vector de tamanho size, preenchido com \n
    sprintf(fileName.data(), "%s/%s%s-%05u.%s", filePath.c_str(), filePrefix.c_str(), date, this->image_counter++, fileExtension.c_str());
    cv::imwrite(fileName.data(), frame);
    //Não é necessário dar delete, quando o vector sair de escopo ele liberará a memória
    

    But in this case the code generated is a little lower.

        
    11.10.2016 / 12:23
    0

    In C ++ I would do the following:

    string fileName = filePath + "/" + filePrefix + date + to_string(image_counter++) + fileExtension + "\n";
    cv::imwrite(fileName.c_str(), frame);
    

    One weakness of the code above is that the counter is not formatted with 5 positions. I think there is no easy and legal way to solve this in pure C ++, without using sprintf, and even with sprintf I think half gambiarra. One way without using sprintf is this:

    string counter = to_string(image_counter++);
    string zeros(5-counter.size(), '0'); // supoe que counter nao vai ser maior que 99999
    string fileName = filePath + "/" + filePrefix + date + zeros + counter + "." + fileExtension + "\n";
    cv::imwrite(fileName.c_str(), frame);
    
        
    12.10.2016 / 06:40