Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > какой из 2-х способов выбрать


Автор: yngwie19 6.11.2008, 16:58
Всем привет. Есть сласс Employee реализованный двумя способами:
1) Выделение памяти для данных-элементов в динамической памяти.
2) Выделение памяти для данных-элементов в стеке.


Код

class Employee  // Пример 1. 
{
    public:
        Employee(char*, char*);
        void Print();
    private:
        char* fn, *ln;
};

int main()
{    
    Employee e1("Yngwie","Malmsteen");
    e1.Print();
    
    return 0;
}

Employee::Employee(char* firstname, char* lastname)
{
    fn = firstname;
    ln = lastname;
}

void Employee::Print()
{
    cout<<fn<<endl;
    cout<<ln<<endl;
}


Пример 2 (Пямять выделена динамически)

Код

class Employee // Пример 2
{
    public:
        Employee(char*, char*);
        ~Employee();
        void Print();
    private:
        char* fn, *ln;
};
int main()
{    
    Employee e1("Yngwie","Malmsteen");
    e1.Print();
    
    return 0;
}

Employee::Employee(char* firstname, char* lastname)
{
    fn = new char[strlen(firstname)+1];
    strcpy(fn,firstname);
    
    ln = new char[strlen(lastname)+1];
    strcpy(ln,lastname);
}
Employee::~Employee()
{
    delete []fn;
    delete []ln;
}
void Employee::Print()
{
    cout<<fn<<endl;
    cout<<ln<<endl;
}


Собственно что бы посоветовали использовать с точки зрения быстродействия и производительности в данной ситуации, динамическую память или стек?

Автор: mes 6.11.2008, 17:04
Класс из первого примера не корректен. Вы инициализируете указатели, адресом внешнего объекта. И поэтомуу уследить когда указатель станет невалидным Вы не сможете.

Добавлено через 6 минут и 56 секунд
во втором Вы храните копию строки - правильно... но Вам не хватает конструктора копий и Вас будет ждать сюрприз, когда Вы после копирования объекта :
Вначале оба объекта (оригинал и копия( будут разделять общие строки, а после удаления одного из них (удалятся и данные) указатели второго будут не валидны.

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

Добавлено через 8 минут и 11 секунд
а вобще лучше вместо char * используйте std::string.

Добавлено через 13 минут и 49 секунд
Цитата(yngwie19 @  6.11.2008,  16:58 Найти цитируемый пост)

Собственно что бы посоветовали использовать с точки зрения быстродействия и производительности в данной ситуации, динамическую память или стек?

Я бы посоветовал не думать о быстродействии и производительности как о самоцели. Выйгрыша тут Вы не найдете. 

Автор: bsa 6.11.2008, 18:25
yngwie19, поддерживаю mes. А по поводу стрингов:
Код
class Employee // Пример 2
{
public:
    Employee(const std::string &f, const std::string &l) : fn(f), ln(l) {}
    void Print() { std::cout << fn << '\n' << ln << std::endl; }
private:
    std::string fn;
    std::string ln;
};

int main()
{    
    Employee e1("Yngwie","Malmsteen");
    e1.Print();
    
    return 0;
}
Видишь, как все просто?

Автор: yngwie19 6.11.2008, 18:31
Мне просто хотелось реализовать по возвожности без включения дополнительных библиотек, т.к это ведет в увеличению кода при компоновке

Автор: J0ker 6.11.2008, 19:29
Цитата(yngwie19 @ 6.11.2008,  18:31)
Мне просто хотелось реализовать по возвожности без включения дополнительных библиотек, т.к это ведет в увеличению кода при компоновке

тогда вам надо все это написать в машинных кодах - тогда вы даже без компилятора и линкера сможете обойтись  smile

Добавлено через 3 минуты и 9 секунд
да, и пример 1 - кривой по определению - вы не можете гарантировать, что в конструктор будут переданы статические данные

Автор: yngwie19 6.11.2008, 20:25
J0ker, а если их сделать статичскими, определить в файле?

Автор: mes 6.11.2008, 20:42
Цитата(yngwie19 @  6.11.2008,  18:31 Найти цитируемый пост)
Мне просто хотелось реализовать по возвожности без включения дополнительных библиотек, т.к это ведет в увеличению кода при компоновке 

если пишете обычную программу для обычного (персонального) компа, то 
1. увеличенный (в разумных пределах) размер не ухудшает прогу
2. использование стандартной библиотеки stl (std:: ) не приведет к значительному увеличению кода, так как она шаблонная.
3. функцию которая реализована в библиотеке, все равно Вы будете реализовывать, и увеличение кода неизбежно.
4. принципиально отказавшись от библиотек Вы обрекаете себя на  изготовление велосипеда.
5..
 smile 

Автор: yngwie19 6.11.2008, 20:47
mes, Спасибо большое за объяснение, мне все же не очень понятно, почему первый пример моего класса не коректен

Автор: mes 6.11.2008, 20:50
Цитата(yngwie19 @  6.11.2008,  20:25 Найти цитируемый пост)
если их сделать статичскими, определить в файле? 

сравните разницу использования char* и std::string для строки . 
Вы хотите все контролировать вручную, как в случае с char* и делать кучу черной работы или просто управлять автоматизированным процессом, как в случае с std::string
Если Вы выбрали первое, то задайте себе вопрос зачем Вам вобще Cpp , если не хотите использовать преимуществ которые он дает?

Автор: yngwie19 6.11.2008, 20:54
mes, Я может и буду использовать все возможности, которые дает С++, но мне хочется также разобраться в процессе контроля вручную, поясните пожалуйста в чем может быть ошибка при проектировании первого варианта класса Employee.

Спасибо

Автор: J0ker 6.11.2008, 20:56
Цитата(yngwie19 @ 6.11.2008,  20:25)
J0ker, а если их сделать статичскими, определить в файле?

статическими где?

объясняю
когда вы передаете в конструктор char* то внутри конструктора невозможно определить, статически данные размещены в памяти по этому адресу или нет. Т.е. в конструктор вы с тем-же успехом можете передать указатель на временные данные, которые рано или поздно станут невалидны, но в объекте на них останется ссылка, что в итоге приведет к неприятностям.

Автор: yngwie19 6.11.2008, 21:01
J0ker, ну дак смотри, когда Я передаю конструктору временные объекты char*, далее они копируются в данные элементы (fn и ln). После завершения работы конструктора локальные переменные уничтожаются, но в объекте я имею нужные значения в полях fn и ln, т.к я скопировал значения до завершения работы конструктора. В чем тогда проблема?

Автор: mes 6.11.2008, 21:02
Цитата(yngwie19 @  6.11.2008,  20:47 Найти цитируемый пост)
почему первый пример моего класса не коректен 


Попробуйте с двумя своими классами этот тест  и думаю  почувствуете разницу :

Код

int main()
{    
   char str[] =  "Yngwie";

    Employee e1(str,"Malmsteen");
    e1.Print();

    str[0] = '_';
    e1.Print();     
    
    return 0;
}

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

Автор: J0ker 6.11.2008, 21:02
вот вам элементарный пример
Код

Employee *foo()
{
    char b[] = "test";
    return new Employee(b, b);
}

int main()
{
    Employee *e = foo();
    ......
    return 0;
}


Добавлено через 1 минуту и 18 секунд
Цитата(yngwie19 @ 6.11.2008,  21:01)
J0ker, ну дак смотри, когда Я передаю конструктору временные объекты char*, далее они копируются в данные элементы (fn и ln). После завершения работы конструктора локальные переменные уничтожаются, но в объекте я имею нужные значения в полях fn и ln, т.к я скопировал значения до завершения работы конструктора. В чем тогда проблема?

я говорю про первый вариант - вы там сохраняете указатели, а не копируете

Автор: mes 6.11.2008, 21:07
Цитата(yngwie19 @  6.11.2008,  21:01 Найти цитируемый пост)
далее они копируются в данные элементы (fn и ln)

Вы копируете значение указателя, а не строку на которую он указывает. 
Например, некто Вам дал почитать конспект.. Вы сделали себе заметку, что на 22й странице есть что-то интересное.
Потом некто вырвал эту страницу. Вы решив обратиться к нужной странице ее не находите .. А завтра экзамен  smile  
Ну а если сделаете копию нужной странички, то дальнейшая судьба оригинала Вас  уже не затронет.  smile 

Автор: J0ker 6.11.2008, 21:08
mes, ты себя в литераторском деле не пробовал?  smile 

Автор: yngwie19 6.11.2008, 21:09
Как мне тогда сделать мой первый класс коректным, используя стек

Добавлено через 2 минуты и 4 секунды
J0ker, нет но если представиться возможность, то обязательно ей  воспользуюсь  smile 

Автор: mes 6.11.2008, 21:12
Цитата(yngwie19 @  6.11.2008,  21:09 Найти цитируемый пост)
Как мне тогда сделать мой первый класс коректным, используя стек 

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

Цитата(J0ker @  6.11.2008,  21:08 Найти цитируемый пост)
mes, ты себя в литераторском деле не пробовал?  smile  

неа, на такое не способен  smile 

Автор: J0ker 6.11.2008, 21:25
Цитата(yngwie19 @  6.11.2008,  21:09 Найти цитируемый пост)
Как мне тогда сделать мой первый класс коректным, используя стек

Код

class Employee  // Пример 1. 
{
    public:
        Employee(char*, char*);
        void Print();
    private:
        char fn[20];
        char ln[20];
};

если объект будет размещен на стеке массивы так-же будут на стеке
но копировать все равно придется

Автор: bsa 6.11.2008, 22:33
У примера, который привел J0ker, есть один недостаток - ограничение на размер строки в 19 символов (20-й это символ конца строки)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)