Ошибки конструктора присваивания C ++ Valgrind - PullRequest
0 голосов
/ 08 января 2019

Я пытаюсь создать свой собственный вектор для тренировочных целей. Все прошло нормально, но теперь я хотел проверить вектор, который также содержит объекты, которые выделяют память.

Моя проблема заключается в конструкторе присваивания этого класса (1), который был вызван в конструкторе тестового вектора.

test_vec.h:

#ifndef TEST_VEC
#define TEST_VEC

#include <cstddef>

template<class T>
class vector
{
public:
    explicit vector(size_t count, const T& value)
        : m_size(count)
        , m_capacity(count)
        , raw_data(static_cast<T*>(operator new(count * sizeof(T))))
    {
        for (size_t i = 0; i < count; ++i) {
            raw_data[i] = value; //(1) Calls the assignment constructor
        }
    }

    ~vector()
    {
        //clearing objects not implemented yet
        operator delete(raw_data);
    }
private:
    size_t m_size;
    size_t m_capacity;
    T* raw_data;
};

#endif

main.cpp:

#include "test_vec.h"

class TestClass {
public:
    TestClass(size_t number) {
        testMem = new size_t[10];
        for (size_t i = 0; i < 10; ++i) {
            testMem[i] = 0;
        }
        testMem[1] = number;
    }
    TestClass(const TestClass& other) {
        testMem = new size_t[10];
        for (size_t i = 0; i < 10; ++i) {
            testMem[i] = other.testMem[i];
        }
    }
    TestClass& operator=(const TestClass& other) {        
        if (this != &other) {
            //I know this is not exception safe at the moment
            delete[] testMem; //(2) delete earlier assigned memory 
            testMem = new size_t[10];

            for (size_t i = 0; i < 10; ++i) {
                testMem[i] = other.testMem[i];
            }
        }
        return *this;
    }
    ~TestClass() {
        delete[] testMem;
    }
    size_t number() const {
        return testMem[1];
    }
private:
    size_t* testMem = NULL;

};

int main() {
    TestClass t1(4); //(4)
    TestClass t2(3);

    t1 = t2;

    vector<TestClass> vec_TestClass(1, TestClass(3)); //(3)
}

Все прошло хорошо. Но в (3) Вальгринд жалуется на «Условный переход или перемещение зависит от неинициализированных значений». Это правильно, потому что testMem не инициализируется в тот момент, когда я хочу назначить объект. Но когда я комментирую delete out (2), я получаю утечку памяти из (4). Это тоже правильно.

Как я могу решить эту проблему, чтобы оба случая обрабатывались?

Спасибо и приветствия

Ответы [ 3 ]

0 голосов
/ 08 января 2019

Нет такой вещи как «конструктор присваивания». Я понимаю, что вы можете возиться с неинициализированной памятью, но вам все равно нужно вызывать правильные конструкторы. В вашем случае проще всего было бы использовать std:::uninitialised_fill_n

#include <memory>

explicit vector(size_t count, const T& value)
    : m_size(count)
    , m_capacity(count)
    , raw_data(static_cast<T*>(operator new(count * sizeof(T))))
{
    std::uninitiliased_fill_n(raw_data, count, value);
}

Также обратите внимание, что ваш векторный деструктор также должен уничтожать любые объекты, которые он построил.

0 голосов
/ 08 января 2019

Хорошо. Я думаю, что это называется оператором присваивания. Ошибка в том, что TestClass не имеет конструктора по умолчанию. Я исправил это, и все прошло хорошо. Я заменил операторы new и delete на функции rihgt. Я сократил свой вектор для этого маленького примера. Конструктор копирования также.

Спасибо. Намек, что мне нужен конструктор по умолчанию, был решением.

0 голосов
/ 08 января 2019

Почему это static_cast<T*>(operator new(count * sizeof(T))), а не собственно new T[count]? Вы никогда не создаете никаких T s! TestClass тоже не тривиально, поэтому его нужно построить. Вальгринд, кажется, знает это.

operator new и operator delete предназначены для распределителей, а не для пользователей. Они просто создают блок памяти, без объектов. Используйте new и delete (или, в реальном коде, стандартные контейнеры!).

Кроме того, ваш класс vector не имеет конструктора копирования. Таким образом, любая копия vector имеет неинициализированный недопустимый указатель члена raw_data. Это не проблема в вашем тестовом примере, но в целом.

Кроме того, не существует такого понятия, как конструктор присваивания. Либо ты строишь, либо назначаешь!

...