crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
> как протестировать оператор присваивания и конструктор копирования класса?
Litkevich Yuriy
  опции профиля:
сообщение 20.4.2010, 15:36
Сообщение #1


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9655
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Собственно вопрос: как протестировать класс на корректность работы самописаных конструктора копирования и оператора присваивания, и на предмет их существования вообще.

Положим, что в конструкторе класса создаётся динамический объект, а в деструкторе удаляется.

Если свои конструктора копирования и оператора присваивания не определять, то компилятор будет использовать побитовое копирование.

При этом могут возникать коварные ситуации. Как я понимаю, связанные с двойным освобождением ресурсов.

Можно ли написать код, который бы осуществлял подобный тест?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Andrewshkovskii
  опции профиля:
сообщение 20.4.2010, 15:52
Сообщение #2


Активный участник
***

Группа: Участник
Сообщений: 351
Регистрация: 27.12.2008
Пользователь №: 467

Спасибо сказали: 18 раз(а)




Репутация:   1  


http://www.devexp.ru/2010/03/o-kopirovanii-obektov-v-c/
вот тут кое-что интересное о копировании объектов и присваивании.

Сообщение отредактировал Andrewshkovskii - 20.4.2010, 15:57
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Влад
  опции профиля:
сообщение 20.4.2010, 17:16
Сообщение #3


Участник
**

Группа: Участник
Сообщений: 146
Регистрация: 20.3.2009
Из: Санкт-Петербург
Пользователь №: 627

Спасибо сказали: 46 раз(а)




Репутация:   8  


Цитата(Litkevich Yuriy @ 20.4.2010, 15:36) *
Если свои конструктора копирования и оператора присваивания не определять, то компилятор будет использовать побитовое копирование.

Не совсем так. Компилятор будет использовать почленное копирование. Для POD-типов он вполне может оптимизировать его до побитового, типа inline memcpy - например, MSVC++ именно так и делает.

Добавлено:
для тестирования корректности работы отдельных функций, к каковым как раз и относятся упомянутые, применяй юнит-тестирование.
Вот одна из (легких) библиотек для юнит-тестирования: UnitTest++, http://unittest-cpp.sourceforge.net/
Или посмотри на Boost.Test: http://www.boost.org/doc/libs/1_34_0/libs/.../doc/index.html

Сообщение отредактировал Влад - 20.4.2010, 17:23
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 20.4.2010, 17:41
Сообщение #4


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9655
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


я пока примитивный тест сделал (мой класс - простенький буфер):
1) проверяем правильность копирования (идентичность копии)
2) модифицируем исходный буфер, новый не должен поменяться
3) модифицируем новый буфер, исходный не должен поменяться

Если я закоментирую оператор присваивания и конструктор копирования, два последних теста не проходят (как и ожидалось).
Код весь находится в функции main и выглядит примерно так:
    // тестируем конструктор копирования
    {
        // инициализируем буфер масивом
        YBuffer1 buffer(rowBuffer, SIZE);
        YBuffer1 bufferCopy(buffer);
        // проверяем правильность копирования
        ok = true;
        for (i = 0; i < SIZE; i++){
            if (bufferCopy[i] != buffer.at(i)){
                ok = false;
            }
        }
        if (ok){
            qDebug() << "test COPY CONSTRUCTOR, coping - passed";
        }else{
            qDebug() << "test COPY CONSTRUCTOR, coping - ERROR";
        }
        const unsigned int index1 = SIZE/2;
        // модифицируем исходный, новый не должен поменяться
        char originalFirst = buffer.at(index1);
        buffer[index1] = ~buffer.at(index1);
        if (bufferCopy.at(index1) == originalFirst){
            qDebug() << "test COPY CONSTRUCTOR, modifying original - passed";
        }else{
            qDebug() << "test COPY CONSTRUCTOR, modifying original - ERROR";
        }        
        
        // модифицируем новый, исходный не должен поменяться
        const unsigned int index2 = index1/2;
        char originalSecond = buffer.at(index2);
        bufferCopy[index2] = ~bufferCopy.at(index2);
        if (buffer.at(index2) == originalSecond){
            qDebug() << "test COPY CONSTRUCTOR, modifying new - passed";
        }else{
            qDebug() << "test COPY CONSTRUCTOR, modifying new - ERROR";
        }        
    }// конец теста    
...
//ещё несколько тестов
Т.е. я ограничил область видимости каждого теста фигурными скобками, и полагал, что по выходу за эти скобки, программа должна аварийно завершатся при отсутствии собственных конструктора копирования и оператора присваивания. Но программа падает почему-то после всех тестов, а не когда произойдёт выход за фигурные скобки.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Влад
  опции профиля:
сообщение 20.4.2010, 18:06
Сообщение #5


Участник
**

Группа: Участник
Сообщений: 146
Регистрация: 20.3.2009
Из: Санкт-Петербург
Пользователь №: 627

Спасибо сказали: 46 раз(а)




Репутация:   8  


Гмм.... А можно взглянуть на код этого YBuffer1?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
DIMEDROLL
  опции профиля:
сообщение 20.4.2010, 18:30
Сообщение #6


Участник
**

Группа: Участник
Сообщений: 165
Регистрация: 28.9.2008
Из: Киев
Пользователь №: 304

Спасибо сказали: 23 раз(а)




Репутация:   0  


Цитата(Litkevich Yuriy @ 20.4.2010, 17:41) *
я пока примитивный тест сделал (мой класс - простенький буфер):

я бы поступил так:
- Для классов которые не должны копироваться использую DISALLOW_COPY_AND_ASSIGN
- Для копируемых темплейтная фукция:
template<typename T>
void TestCopyAndAssign(const T & obj) {
  T copy(obj);
  assert((copy == obj) && "Testing copy failed");
  T assign;
  assign = obj;
  assert((assign == obj) && "Testing assign failed");
}

Весь код проверки находится в операторе сравнения(==). Для каждого класса не надо писать свою функцию теста, просто реализовать ==.
В реализации == обязательно проверять указатели на равенство. Например
class A {
public:
  B *b;
  //... all operators
  bool operator==(const A &obj) {
    assert((this->b != obj.b) && "Shit happened, object copying or assigning doesn't handle pointers");
    return *this->b == *obj.b;
  }
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 20.4.2010, 18:52
Сообщение #7


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9655
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Влад @ 20.4.2010, 22:06) *
Гмм.... А можно взглянуть на код этого YBuffer1?
можно, заодно может на косяки укажите:
ybuffer1.h
#ifndef YBUFFER1
#define YBUFFER1

/**    Класс YBuffer1 является ... .
*     Этот класс ...
*/
class YBuffer1
{

public:
    YBuffer1(const char *abuffer, unsigned int asize);
    ~YBuffer1();
    YBuffer1(const YBuffer1 &other);
    YBuffer1 &operator=(const YBuffer1 &other);
    
    const char& at(unsigned int i) const;
    char& operator[](unsigned int i);
    char operator[](unsigned int i) const;
    
    unsigned int size() const {return theSize;}

private:
    unsigned int theSize;
    char *theBuffer;

private:
    void copy(const YBuffer1 &source, YBuffer1 &destination);

};

#endif //YBUFFER1

ybuffer1.cpp
#include "ybuffer1.h"

#include <QtGlobal>


YBuffer1::YBuffer1(const char *abuffer, unsigned int asize)
{
    theSize = asize;
    theBuffer = new char[asize];
    // тут надо скопировать содержимое
    unsigned int cnt = 0;
    while(cnt != asize){
        theBuffer[cnt] = abuffer[cnt];
        cnt++;
    }
}

YBuffer1::~YBuffer1()
{
    delete theBuffer;
}

YBuffer1::YBuffer1(const YBuffer1 &other)
{
    theSize = other.size();
    theBuffer = new char[other.size()];
    // тут надо скопировать содержимое
    copy(other, *this);
}

YBuffer1& YBuffer1::operator=(const YBuffer1 &other)
{
    theSize = other.size();
    theBuffer = new char[other.size()];
    // тут надо скопировать содержимое
    copy(other, *this);
    return *this;
}

void YBuffer1::copy(const YBuffer1 &source, YBuffer1 &destination)
{
    unsigned int size = source.size();
    Q_ASSERT_X(size == destination.size(), "YBuffer1::copy()", "size of objects not eqal");
    unsigned int cnt = 0;
    while(cnt != size){
        destination[cnt] = source[cnt];
        cnt++;
    }
}

const char& YBuffer1::at(unsigned int i) const
{
    Q_ASSERT_X(i <= theSize, "YBuffer1::at()", "requested index too big");
    const char &data = theBuffer[i];
    return data;
}

char& YBuffer1::operator[](unsigned int i)
{
    Q_ASSERT_X(i <= theSize, "YBuffer1::operator[]", "requested index too big");
    char &data = theBuffer[i];
    return data;
}

char YBuffer1::operator[](unsigned int i) const
{
    Q_ASSERT_X(i <= theSize, "YBuffer1::operator[]", "requested index too big");
    char data = theBuffer[i];
    return data;
}


Цитата(DIMEDROLL @ 20.4.2010, 22:30) *
Для копируемых темплейтная фукция:
эта шаблонная функция ничего не даст, в отсутствии самописанных конструктора копирования и оператора присваивания

Цитата(DIMEDROLL @ 20.4.2010, 22:30) *
Весь код проверки находится в операторе сравнения(==).
про это не понял, где и как применяется
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
DIMEDROLL
  опции профиля:
сообщение 20.4.2010, 18:59
Сообщение #8


Участник
**

Группа: Участник
Сообщений: 165
Регистрация: 28.9.2008
Из: Киев
Пользователь №: 304

Спасибо сказали: 23 раз(а)




Репутация:   0  



Цитата
Цитата(DIMEDROLL @ 20.4.2010, 22:30) *
Для копируемых темплейтная фукция:
эта шаблонная функция ничего не даст, в отсутствии самописанных конструктора копирования и оператора присваивания

Если программист не пишет реализацию конструктора копирования и оператора присваивания, то он подразумевает что по вариант по умолчанию его устраивает, либо должен явно запретить копирование и присваивание макросом(как я указал)
помоему это является хорошим стилем кодирования..

Цитата
Цитата(DIMEDROLL @ 20.4.2010, 22:30) *
Весь код проверки находится в операторе сравнения(==).
про это не понял, где и как применяется


Я имел ввиду: если operator== работает правильно, то его можно использовать в моей шаблонной функции для проверки копирования и присваивания
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 20.4.2010, 19:03
Сообщение #9


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9655
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(DIMEDROLL @ 20.4.2010, 22:59) *
не пишет реализацию конструктора копирования и оператора присваивания, то он подразумевает что по вариант по умолчанию его
собственно, я рассматриваю, отсутствие, как частный (а может и вовсе жёсткий) случай неправильной реализации КК и ОП. Т.е. должен быть какой-то чёткий эффект если что-то сделано не верно.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
DIMEDROLL
  опции профиля:
сообщение 20.4.2010, 19:07
Сообщение #10


Участник
**

Группа: Участник
Сообщений: 165
Регистрация: 28.9.2008
Из: Киев
Пользователь №: 304

Спасибо сказали: 23 раз(а)




Репутация:   0  


Цитата(Litkevich Yuriy @ 20.4.2010, 19:03) *
собственно, я рассматриваю, отсутствие, как частный (а может и вовсе жёсткий) случай неправильной реализации КК и ОП. Т.е. должен быть какой-то чёткий эффект если что-то сделано не верно.

что такое КК и ОП?
Цитата
Т.е. должен быть какой-то чёткий эффект если что-то сделано не верно.

Что-то это что?
чёткий эффект это какой?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 22.7.2019, 20:08