LINUX.ORG.RU

[C++] Странности в классах


0

2

Имеется некий класс A

class A
{
    private: int i;
    public: 
        A(){ i = 1;}
        A(const A & a){ i = a.i; }
        A(int j) { i = j;}

        bool Do()
        { 
            if (i >= 0) 
                return true; 
            else 
                return false; 
        }
};

Все прекрасно работает, но иногда при обработке, где в дебрях большой программы падаем в методе Do() с ошибкой Segmentation fault.

При этом утверждается что i <- <unavailable synchronous data> (программа запущена в 1 поток)

Подскажите пожалуйста, как локализовать данную ошибку ? Спасибо.


> Подскажите пожалуйста, как локализовать данную ошибку ? Спасибо.

Подозреваю, с помощью valgrind и подобных ему инструментов.

nozh ()

ну, во-первых, неплохо это переписать вот так:

class A {
public: 
	A() : i_(1)
	{}
	
	explicit A(int j) : i_(j)
	{}
	
	A(const A &a) : i_(a.i_)
	{}

	A &operator=(const A &a)
	{
		i_ = a.i_;
		return *this;
	}

	bool doWork()
	{
		return i_ >= 0;
	}

private:
	int i_;
};

за исключением метода, названным зарезервированным словом, особых проблем не вижу

vvviperrr ★★★★★ ()

> ... где в дебрях большой программы падаем в методе do() с ошибкой Segmentation fault.

мб метод вызывается по некорректному указателю (не инициализирован, используется после delete итп).

arsi ★★★★★ ()
Ответ на: комментарий от Lorchanko

Не пугай так больше. Я уж подумал это правда.

anonymous ()
Ответ на: комментарий от vvviperrr

i_

Лучше уж тогда нормальные имена давать, чем это.

Kosyak ★★★★ ()

Может сдох объект, метод которого ты вызываешь? Посмотри valgrind-ом, он такие места хорошо показывает.

staseg ★★★★★ ()
bool Do()
{
    if (i >= 0) 
        return true; 
    else 
        return false;
}

глаза режет. Лучше

bool Do() {
    return i >= 0;
}

SSN ()

Нормально работает код. «i = a.i» работает, т.к. класс является дружественным сам себе (friend), но лучше это не использовать, если возможно, т.к. это нарушение принципов ООП.

Программа у вас явно падает не из-за этого кода, он корректен. Скорее всего где-то удаляется объект этого класса, а потом вы пытаетесь по несуществующему адресу (указателю) получить доступ к объекту (разыменовать несуществующий указатель). Попробуйте запустить под отладкой и посмотреть стек вызовов, когда прога навернется.

Код конечно некрасивый, лучше было бы так:

#include <cstdlib>
#include <iostream>

class A
{
public:
    A();
    explicit A(const A &a);
    explicit A(int i);

    bool test() const;
    int value() const;

private:
    int m_i;
};

A::A()
    : m_i(1)
{
}

A::A(const A &a)
    : m_i(a.m_i)
{
}

A::A(int i)
    : m_i(i)
{
}

bool A::test() const
{
    return m_i >= 0;
}

int A::value() const
{
    return m_i;
}

int main(int argc, char *argv[])
{
    // Hide warning of unused variables
    (void)argc;
    (void)argv;

    A a1(123);
    A a2(a1);

    std::cout << "a2 value is " << a2.value() << std::endl;

    return EXIT_SUCCESS;
}

skb7 ()
Ответ на: комментарий от skb7

> Нормально работает код. «i = a.i» работает, т.к. класс является дружественным сам себе (friend), но лучше это не использовать, если возможно, т.к. это нарушение принципов ООП.

Я бы сказал, что это нормально. Ибо конструктор копирования - это не просмот свойст объекта

namezys ★★★★ ()
Ответ на: комментарий от namezys

Точно, не подумал. Для копирующего конструктора это нормально.

skb7 ()
Ответ на: комментарий от vvviperrr

Ну если нужно иметь возможность сделать:

A a2 = a1;
то да, нужно убрать explicit у копирующего конструктора. Поскольку я явно указал:
A a2(a1)
то explicit не мешает.

skb7 ()
Ответ на: комментарий от jtootf

low coupling/high cohesion - это не принципы ООП, это принципы проектирования в целом, которые были известны задолго до возникновения ООП. И не совсем понятно, при чем тут эти 2 принципа? Я согласился уже, что для копирующего конструктора вполне нормально получать доступ к закрытым членам класса переданного объекта, иначе пришлось бы делать геттеры для каждого поля класса, что засоряло бы интерфейс класса. Я имел ввиду, что *в общем* получать доступ к приватным членам другого объекта - это нарушения принципа ООП об инкапсуляции.

skb7 ()
Ответ на: комментарий от skb7

это не принципы ООП, это принципы проектирования в целом

но мы же про ООП говорим, не? к тому же, в других областях эти принципы не называются так уродливо

Я имел ввиду, что *в общем* получать доступ к приватным членам другого объекта - это нарушения принципа ООП об инкапсуляции

это утверждение, вообще говоря, не менее абсурдно чем предыдущие. как бы там ни было, в данном примере инкапсуляция вообще не к месту: инкапсулировать класс от самого себя по меньшей мере глупо, изменение реализации автомагически синхронизирует и интерфейс доступа к ней

jtootf ★★★★★ ()
Ответ на: комментарий от yoghurt

>>A(const A & a){ i = a.i; } i - приватный член класса, a.i - неправильно.

Стыдоба, лучше бы ты этого не писал

Sr. developer, наверное... Так что можно :)

yaws ()
Ответ на: комментарий от skb7

>Нормально работает код. «i = a.i» работает, т.к. класс является дружественным сам себе (friend), но лучше это не использовать, если возможно, т.к. это нарушение принципов ООП.

Смело

yoghurt ★★★★★ ()
Ответ на: комментарий от yoghurt

Подумаешь, может у человека неприязнь к неявным преобразованиям через конструктор копирования. Несколько раз видел таких людей.

staseg ★★★★★ ()
Ответ на: комментарий от staseg

>у человека неприязнь к неявным преобразованиям через конструктор копирования

Суть не в этом. Убивается возможность получать/передавать/возвращать такие объекты по значению

// не узнаю ЛОР.

yoghurt ★★★★★ ()
Ответ на: комментарий от yoghurt

>не узнаю ЛОР

Ой, я лопух. Читаю/пишу о конструкторе копирования, а думаю о конструкторе преобразования.

staseg ★★★★★ ()
Ответ на: комментарий от staseg

На самом деле для копирующего конструктора я explicit не подумав поставил, когда ставил explicit для A(int i). Я знаю к чему это приводит прекрасно, но как я уже написал выше, в данном примере это абсолютно неважно, т.к. я явно вызывал конструктор в main(). В реальном проекте эту ошибку я быстро вычислил бы, написав A a = b; и убрал бы explicit. Короче это просто опечатка, для данного примера ИМХО некритичная.

Про ООП - я имел ввиду по аналогии с доступом в копирующем конструкторе к приватным членам класса, что не стоит использовать механизм френдов без крайней нужды, в копирующем конструкторе конечно же это нормально.

skb7 ()

Скажите g++ "-fstack-protector-all" и велика вероятность, что упадет в правильном месте. А если нет, то тогда Valgrind.

br0adcast007 ()

называй методы с маленькой буквы, блджад... а то с классами можно спутать.

Obey-Kun ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.