Уфф, спасибо огромное, а то я почти веру в С++ потерял :)
Главное, что статик догадался (по логике вещей), только писал
вызов как test.read(1), компилер ругался. А про двоеточия
мне в голову не пришло, начал уже workaround делать :).
Хотелось собственно вот такого кода - типа чтения из потока:
------------------------------------------------------------
class test
{
int data;
public:
test(){ data = 0; };
test(int a){ data = a; };
static test *read(int a)
{
if( a>0 )
{
return new test(a);
} else return NULL;
}
};
int main(int argc, char* argv[])
{
test *t;
if( (t = test::read(1)) != NULL)
printf("Read OK\n");
else
printf("Read failed!\n");
return 0;
}
-------------------------------------------------------
Кстати, смежный вопрос :) что нужно написать в конструкторе,
чтобы new вернул NULL ?
Типа выделяем в конструкторе память, если облом, то как сказать,
чтобы верхний new тоже выдал облом (или лучше пример с файлом,
т.к. с памятью это и так случится :)
2 gnite:
Выделять память в конструкторе это ошибка, если передаёшь string как параметер то делай так:
#include <iostream>
using namespace std;
class A
{
public:
A(char* str):m_str(str){}
~A(){}
char* m_str;
void printStr(){cout<<m_str<<endl;}
};
int main()
{
A a("string");
a.printStr();
return 0;
}
2 anonymous (*) (2002-05-30 03:25:32.681)
Ню-ню... А потом спрашивают: "отчего же у меня программа падает?"
Данные, которые использует экземпляр класса, нужно хранить локально
(за исключением специальных случаев, но это другой разговор).
Выделение памяти в конструкторе часто - необходимость, т.к. тот кто будет использовать твой класс не должен городить огород типа
MyClass obj;
obj.init ();
- для инициализации класса. Это неудобно, да и забыться можно.
2 ignite
К сожалению, NULL вернуть нельзя. Можно только сгенерить exeption, который потом перехватить:
class A
{
public:
A ()
{
// что нибудь делаем ...
if (errors)
throw "error in constructor";
}
}
А вообще, по этому вопросу, лучше проштудировать Страуструпа.
Совершенно одобрямс romanSA. Инициализация члена класса (указателя)
другим указателем наводит на плохие мысли, особенно если потом этот
указатель разименовывается. Кстати следует обратить внимание на STL -
там фокусов с памятью нет. Если нужно поработать со строками - лучше
уж в качестве типа члена класса исопользовать string (из STL)
А обработку неудачного выделения памяти можно сделать так:
try
{
MyClass a(.....); // в конструкторе есть операторы new
a.some_method(....); // используются члены класса, инициализированные new, если они все еще NULL, то "выбросить" исключение
.....
}
catch(.......)
{
}
На мой взгляд конструкции типа:
>int main(int argc, char* argv[])
>{
> test *t;
....
>t = test::read(1);
лучше вообще избегать, так как не понятно кто будет вызывать delete.
Да и потом замучаешся искать где память течет и что вызывает
segmentation fault
Можно было бы использовать в простых случаях
auto_ptr<test> t(test::read(1));
А в более сложных нужно смастерить "smart pointer" со встроенным
(в test) счетчиком.
К сожалению auto_ptr мне так и не удалось засунуть в какой-нибудь
стандартный контейнер :-(, а было бы не плохо.
Может кто-нибудь знает как это делается ?
2 anonymous (*) (2002-05-31 14:05:30.216)
Насчёт auto_ptr в контейнере: очень стрёмная штуковина.
Дело в том, что этот шаблон устроен примерно так (в разных _реализациях_ STL м.быть по-разному но везде суть одна):
template <class Tptr> auto_ptr
{
...
private:
bool Owns;
Tptr * ptr;
}
Член Owns определяет, является ли экземпляр реализации шаблона владельцем указателя на данные ptr. Если да, то при уничтожении этого объекта будет освобождён и указатель.
Такая вот простота (+ реализация) приводят к тому, что при передаче объекта, созданного с применением auto_ptr в функцию "по значению", владельцем данных становится именно копия, переданная в функцию.
В результате после выхода из функции данные удаляются и исходным объектом уже не попользуешся.