Search code examples
c++windows-7qt5smart-pointersqvector

unique_ptr, qvector.resize() throws error 2280 attempting to reference a deleted function


To prevent scope creep (on a previous Q), I've isolated the above error.

My Voxel class definition:

#ifndef VOXEL_H
#define VOXEL_H

#include <QObject>
#include <QVector>
#include <iostream>
include <memory>

class Voxel : public QObject
{
    Q_OBJECT
public:
    Voxel();
    ~Voxel();
};

#endif // VOXEL_H

The main file which triggers the error:

#include <voxel.h>

int main(int argc, char *argv[])
{
    QVector < QVector <std::unique_ptr <Voxel> > > cVoxel;

    cVoxel.resize(0);

    int rows = 80, cols = 80;

    for (int i = 0; i < rows; i++)
    {
       cVoxel[i].resize(cols);
       for (int j = 0; j < cols; j++)
       {
          cVoxel[i][j].reset(new Voxel);
       }
    }
}

The line ultimately throwing the error is:

cVoxel[i].resize(cols);

The full error trace: (which doesn't say that the error ultimately comes main)

enter image description here

There are other Questions (that are helpful) about this error but I can't fully understand how to resolve it. It would seem that qvector.resize() is attempting to reallocate and likely using a copy constructor which is then throwing this error? I could manually free the memory instead of using the above function, but the whole ideal of using smart pointers is to avoid memory leaks... I started using unique_ptr to address substantial leaking.


I'm using QtCreator 4.4.0 and Qt 5.6.2, 64-bits.

--- EDIT ---

If I replace QVector with std::vector, ie cVoxel is created as:

std::vector < std::vector <std::unique_ptr <Voxel> > > cVoxel;

Then the program crashes in the outer for loop, at:

cVoxel[i].resize(cols);

Debugging reveals that:

Debug Assertion Failed!

Program: C:\windows\system32\MSVCP140D.dll File: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\vector Line: 1234

Expression: vector subscript out of range

For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts.

I can get the code to work by resizing cVoxel to 80 rather than 0. But it appears there's a subtle difference between how QVector.resize() and std::vector.resize() operate. Reading the docs for each, they seemed identical.


Solution

  • unique_ptr cannot be copied (only moved or move-assigned):

    The class (unique_ptr) satisfies the requirements of MoveConstructible and MoveAssignable, but not the requirements of either CopyConstructible or CopyAssignable.

    The copy-constructor and copy-assignment are deleted in unique_ptr hence the error. Copying is implicitly required by cVoxel[i].resize(cols). You could use QVector<QVector<Voxel>> as an alternative.

    Another thing: calling cVoxel[i].resize(cols) after cVoxel.resize(0) is out-of-bounds. You probably need cVoxel.resize(rows).