ffmpeg: «утечка» памяти (av_read_packet) 6

Posted by Андрей on Июль 10, 2008

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

AVPacket *m_pPacket = (AVPacket *)malloc(sizeof(AVPacket))
while(1)
{
     int ret = av_read_frame(formatCtx, m_pPacket);

     if (ret < 0)
         // error

     if (m_pPacket.stream_index == videoStreamIndex)
     {
         .... avcodec_decode_video ...
     }
 }
 av_free_packet(m_pPacket);
 free(m_pPacket);

Так вот, это неправильно, нужно вызывать av_free_packet после каждого av_read_packet:

Continue reading…

Как преподавать C++? 8

Posted by Андрей on Март 30, 2008

Кого мы хотим подготовить, обучая студентов программированию на C++? Что они должны вынести из курса? Мне кажется, важно научить писать программы. Красивые, эффективные, сопровождаемые. Язык – лишь инструмент программирования. И надо научиться пользоваться инструментом. Вот когда в автошколе учат вождению машину, совсем не обязательно знать тонкости устройства шины CAN, обеспечивающей связь всех устройств автомобиля. Да, надо узнать, что такое тормоза, руль, двигатель, но на каких-то деталях надо остановиться, и, самое, главное, надо научиться пользоваться автомобилем (то есть водить автомобиль) безопасно, уверенно и т.п.

А почему мы заставляем студентов знать подробности языка, которые нельзя продемонстрировать на разумном примере? Например, множественное наследование (я уже молчу о виртуальном наследование в сочетании с множественном). Для этого нужны примеры, большие примеры, огромное количество понятий (например, интерфейсы), чтобы студент почувствовал, что и зачем. А мы с упорством сумасшедших рассказываем о том, какие члены классов будут видны или не видны в той или иной ситуации.

Вот объясните мне, кто-нибудь использовал перегрузку наряду с виртуальностью?

class A
{
public:
    virtual int f();
};
class B : public A
{
public:
    virtual int f(double);
};

Что это нормально, это работает? Зачем нужны эти знания? А кто перегружал функции, расположенные в разных областях видимости?

class A
{
    void f(char);
public:
    void f(int);
};

A a;
a.f('a');

Ну кто такое делает в реальных задачах? Зачем студентов заставлять разбирать эти примеры?

Как я понял из интервью Бьерна Страуструпа, это проблема преподавания Computer Science не только на факультете ВМиК МГУ. Он говорит, кого мы готовим? lanugage lawyers? По-моему, это очень точно английское словосочетание… Мы готовим студентов стать членами комитета ISO по стандартизации C++?

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

Кому это нужно? Самоудовлетворение от задалбливания в умы студентов бесполезных знаний?

Почему мы не экзаменуем их на умение программировать? Ну или хотя бы на знание базовых конструкций языка? Зачем такие извращенные примеры? Если бы я опубликовал весь вариант работы, которую писали студенты, думаю, многие были бы в шоке. Я уверяю, что подавляющее большинство потрясающих, талантливых C++-программистов не смогут решить этот вариант на «пять». Но от этого они не становятся хуже, а претензии надо предъявлять тем, кто составил такую программу курса, предъявляет такие требования к студентам. Как они могут полюбить такой предмет?

По-моему, пора остановиться и сменить ориентиры.

C++, просто смешно… 3

Posted by Андрей on Февраль 07, 2008

Что выведет данный код?

#include <stdio.h>

struct A
{
    A(int x = 3) { printf("%d\n", x); }
};

struct B: virtual public A
{
   B() : A(4) {}
}; 


struct C: virtual public A
{
  C() : A(5) { }
}; 

struct D: public B, public C
{

};

int main()
{
    D d;
    B b;
    C c;

    return 0;
}

Ответ:

3
4
5

Что самое смешное, можно из D::D() явно вызвать конструктор A с другим параметром. Наслаждаемся в C++ смесью виртуального наследования, раздельной компиляции и полученной кривости.

Чудеса С++: разные формы вызова конструктора копирования 1

Posted by Андрей on Февраль 04, 2008

Что происходит, когда мы пишем A a(3), A a = 3 и A a = A(3)? Меня этот вопрос давно интересовал. Конечно, у класса должны быть корректные конструкторы, в том числе и копирования, операторы присваивания и т.п.

Проведем следственный эксперимент…

#include <stdio.h>

class A
{
    public:
    A() 
    {
        printf("A::A()\n");
    }

    A(int) 
    {
        printf("A::A(int)\n");
    }

    A(int, int) 
    {
        printf("A::A(int, int)\n");
    }

    A(const A& a) 
    {
        printf("A::A(const A& a)\n");
    }

    void operator=(const A& a) 
    {
        printf("A::operator=(const A& a)\n");
    }
};

int main()
{
    printf("=> A a1;\n");
    A a1;
    printf("=> A a2(3);\n");
    A a2(3);
    printf("=> A a3;\n");
    A a3 = 3;
    printf("=> A a4 = A(3);\n");
    A a4 = A(3);
    printf("=> A a5; a5 = A(3);\n");
    A a5; a5 = A(3);
    printf("=> A a6(a1);\n");
    A a6(a1);
    printf("=> A a7(4,4);\n");
    A a7(4, 4);
    printf("=> A a8 = A(4,4);\n");
    A a8 = A(4, 4);
    return 0;
}

Выведет на экран:

=> A a1;
A::A()
=> A a2(3);
A::A(int)
=> A a3;
A::A(int)
=> A a4 = A(3);
A::A(int)
=> A a5; a5 = A(3);
A::A()
A::A(int)
A::operator=(const A& a)
=> A a6(a1);
A::A(const A& a)
=> A a7(4,4);
A::A(int, int)
=> A a8 = A(4,4);
A::A(int, int)

Т.е. каждый раз вызывается обычный конструктор и все три формы, приведённые в начале поста, эквивалентны.

Однако стоит нам конструктор копирования объявить private, и сразу же получим вот это:

[smir@smira Teaching]$ g++ test.cxx 
test.cxx: In function ‘int main()’:
test.cxx:22: ошибка: ‘A::A(const A&)’ is private
test.cxx:39: ошибка: в данном контексте
test.cxx:22: ошибка: ‘A::A(const A&)’ is private
test.cxx:39: ошибка: в данном контексте
test.cxx:39: ошибка:   initializing temporary from result of ‘A::A(int)’
test.cxx:22: ошибка: ‘A::A(const A&)’ is private
test.cxx:41: ошибка: в данном контексте
test.cxx:22: ошибка: ‘A::A(const A&)’ is private
test.cxx:41: ошибка: в данном контексте

Строка 22 – это объявление конструктора копирования, а 39 и 41 это обращения A a3 = 3 и A a4 = A(3);. Интересно получается, что хотя конструктор копирования и не вызывается, но эти формы требуют его открытости. Это стандарт C++, оптимизация gcc или что-то ещё?