LINUX.ORG.RU

> Как создать функцию-шаблон, принимающую в качестве параметра не переменную, а тип переменной

AFAIK, это невозможно. А как звучит настоящий вопрос?

tailgunner ★★★★★
()

Либо так

template < typename T >
void func()
{
 ...
}

и вызывай
func < T > ()

либо можно извратиться так

template < typename T >
void func1(T * )
{
 ...
}

#define func(T) func1((T*)0)

вызвать так
func(double)

Reset ★★★★★
()

На самом деле мне нужно было переопределить оператор new, и кажется вот это работает:

void* operator new(size_t s)
{
return malloc(s);
}

Вообще хотелось бы иметь возможность писать нечто вроде

template<class T>
T* construct(T)
{
return new T;
}
Но видимо не судьба.

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

>либо можно извратиться так

Как раз то, что искал - спасибо!

anonymous
()

There is no guarantee that new would internally use malloc, or that delete would internally use free.

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

> На самом деле мне нужно было переопределить оператор new, и кажется вот это работает

Ну вообще говоря, так и нужно делать. Таким образом переопределяется глобально оператор new, выделяющий память (но не создающий экземпляры классов).

> Вообще хотелось бы иметь возможность писать нечто вроде

А в чём смысл данной операции? Это же эквивалентно вызову дефолтного "new T".

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

>А в чём смысл данной операции? Это же эквивалентно вызову дефолтного "new T".

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

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

Предыдущий ответ относился к переопределенному new, параметризация типа здесь как бы не причем :s

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

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

template<class T>
T* allocate_and_construct(T*)
{
 void* p = malloc( sizeof( T ) );
 return new( p )T();
}

template<class T>
void destruct_and_deallocate(T* t)
{
 t->~T();
 free( t );
}

и дальше можно делать вот так:

A* p; 
A* a = allocate_and_construct( p );
destruct_and_deallocate( a );

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

> template<class T>
> T* allocate_and_construct(T*)
> {
>  void* p = malloc( sizeof( T ) );
>  return new( p )T();
> }

-1

В конструкторе может кинуться исключение, память никто не вернет.

aton
()

Автору топика хочется пожелать не заниматься велосипедостроением и использовать проверенные решения - http://valgrind.org/

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

> При использовании голого malloc как я понял возникает проблема с виртуальными функциями

malloc используется для выделения памяти, заполнение vtable происходит в момент конструирования объекта

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

>В конструкторе может кинуться исключение, память никто не вернет.

О ужас! Кошмар! Придется использовать try, catch и throw. Это совсем невозможно пережить?

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

> О ужас! Кошмар! Придется использовать try, catch и throw

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

> Это совсем невозможно пережить?

Нет. Сразу об стену.

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

>malloc используется для выделения памяти, заполнение vtable происходит в момент конструирования объекта

На счет malloc тоже возникает большой вопрос. При использовании new конструирование объекта происходит автоматически после выделения памяти для его хранения. Но при использовании моей версии new (только malloc) конструктор все равно вызывается. Например, следующий код:

#include <iostream>

using namespace std;

class Cmplx
{
private:
double im;
double re;
public:
Cmplx(double im=3,double re=4)
{
cout<<"Cmplx Constructor\n";
this->im=im;
this->re=re;
}
double getIm() const {return im;}
double getRe() const {return re;}
};

void* operator new(size_t s)
{
cout<<"New: allocating "<<s<<" bytes\n";
return malloc(s);
}

int main(int argc,char **argv)
{
Cmplx *c=new Cmplx;
cout<<c->getIm()<<endl<<c->getRe()<<endl;
return 0;
}

выводит:

New: allocating 16 bytes
Cmplx Constructor
3
4

Проверено в gcc и Visual C++. Вопрос: кто вызывает конструктор в этом случае?

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

Дубль два:
#include <iostream>

using namespace std;

class Cmplx
{
   private:
      double im;
      double re;
   public:
      Cmplx(double im=3,double re=4)
      {
         cout<<"Cmplx Constructor\n";
         this->im=im;
         this->re=re;
     }
    double getIm() const {return im;}
    double getRe() const {return re;}
};

void* operator new(size_t s)
{
   cout<<"New: allocating "<<s<<" bytes\n";
   return malloc(s);
}

int main(int argc,char **argv)
{
    Cmplx *c=new Cmplx;
    cout<<c->getIm()<<endl<<c->getRe()<<endl;
    return 0;
}

выводит:

New: allocating 16 bytes
Cmplx Constructor
3
4 

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

А с чего ты решил, что в данном случае конструктор никто не должен вызывать?

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

new это оператор, который вызывает функцию operator new для выделения памяти под объект, затем вызывает конструктор. Переопределить можно только функцию operator new. Оператор new переопределить невозможно, так как это оператор а не функция. Вот такой вот каламбур :)

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

>new это оператор, который вызывает функцию operator new для выделения памяти под объект, затем вызывает конструктор.

Где это написано?

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

В стандарте, очень рекомендую к изучению :)

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

> Лушче посмотри на auto_ptr из STL и разные ptr'ы из boost

+1

ИМХО, отслеживанием выделения/освобождения памяти должен заниматься компилятор/библиотека, а не программист.

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

Я вот к этому сказал. В тему-таки или нет?

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

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

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

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

> Лучше посмотреть на D :)

common lisp - всему голова :)

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

>> Лушче посмотри на auto_ptr из STL и разные ptr'ы из boost

> Лучше посмотреть на Boehm's GC.

Он умеет вызывать деструкторы? O_O

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

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

На самом деле мне нужно уметь находить утечки. В перспективе, возможно понадобится ручное управление кучей (если не будет устраивать производительность), если это возможно, но пока что ограничусь стандартными средствами C++.

>common lisp - всему голова :)

Lisp нетехнологичен.

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

Если утечки нужно находить при написании - то пользуйся чем и все - valgrind. Хороший инструмент. Если нужно во время работы.. ты планируешь их много оставлять для runtime'а? Может быть лучше тогда взять язык с gc?

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

>>> Лушче посмотри на auto_ptr из STL и разные ptr'ы из boost
>> Лучше посмотреть на Boehm's GC.
> Он умеет вызывать деструкторы? O_O

да, но не всегда :) посмотри /usr/include/gc/gc_cpp.h:
A collectable object may have a clean-up function, which will be
invoked when the collector discovers the object to be inaccessible.
An object derived from "gc_cleanup" or containing a member derived
from "gc_cleanup" has a default clean-up function that invokes the
object's destructors. Explicit clean-up functions may be specified as
an additional placement argument:

A* a = ::new (GC, MyCleanup) A;

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

>На самом деле мне нужно уметь находить утечки. В перспективе, >возможно понадобится ручное управление кучей (если не будет >устраивать производительность), если это возможно, но пока что >ограничусь стандартными средствами C++.

1)(один) У меня была аналогичная проблема (VC++). Советую дописать дефолтный макрос DEBUG_NEW, если ты в вижуалсях. Я так и сделал(деталей, извини, не помню). На других компиляторах и идЭешниках , кстати, скорее всего есть аналогичные инструменты. Если в твоём нема, см. вижуалсишный DEBUG_NEW и делай свой по образу и подобию.

2)(два) Может и не в тему, конечно, но... Не советую переопределять new создающий, который для объектов класса, ИМХО жуткий гемор. Почитай теорию (Страуструп, Мейерс и т.д.). там сказано, что для энтого гемора, следует переопределить целый КОМПЛЕКС: new канонический throw std::bad_alloc, new размещающий, new nothrow и delete. Вроде так. Причём если перегрузил один из вышеуказанных, будь добёр и остальные иначе быть попе.

3)(три) Советую также, подумать, а насколько опасна тебе эта самая утечка. Например, в виндах, KDE, других user-time ситемах очень часто на утечку памяти моно забить, т.к. там на 2-ом уровне ядра живёт бог (или баг) по имени "МЕнеджер памяти", который с удовольствием разгребёт твой мусор. Это ещё вопрос, что считать утечкой.

4)(чтыре) Если же ты действительно провёл все необходимые тесты своих структур данных и они однозначно указывают на необходимость динамического освобождения динамически выделенной памяти, подумай об использовании патерна boost::shared_ptr( вроде я видел такой свет в этом топике? ). Если boost::shared_ptr реально снижает эффекимвность, рассмотри Loki::smart_ptr

5)(пять) "Перспектива ручного управления кучей" - это ... ЭЭЭЭ ... ну очень говёная перспектива. Хуже перспективы не придумаешь. Советую крепко подумать, как этого избежать. Дело в том, что я имею грёбаный опыт создания ручных MemoryPool-ов для "no-systemd"-контроллеров на базе C51 и AVR-Risc. Это были приложения для различных "переходников" типа южного/северного мостов в маме-плате. Так вот, там НУЖНО было создавать объекты динамически, но НИКАКИЕ языковые средства для этого не подходили по вполне понятным причинам. Ни тебе маллок, ни нью. Ты прсто не представляешь, сколько граблей было перелопачено.. Вывод: НЕ СТОИТ УПРАВЛЯТЬ КУЧЕЙ ВРУЧНУЮ.

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

И ещё вот что. В библиотеке Loki есть феноменально-замечательный, платформенно-независимый, полностью соответсвующий стандарту c++, менеджер памяти для малых объектов. Использую эту прелесть в соих прогах - эффективность сильно улучшится.

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

>Лушче посмотри на auto_ptr из STL и разные ptr'ы из boost

Вощета std::auto_ptr функционально ограниченн своей семантикой разрушающего копирования. Например, его нельзя в контейнерах хранить.

boost::shred_ptr<T> - это хорошо, пока тебя

1.не волнует эффективность работы с кучей

2.ты не планируешь юзать объекты класса Т в многопоточных приложениях.

Насколько я понял, 1) - актуально для автора топика. В будущем возможно понадобится и 2). Чтобы раз и навсегда решить эти проблемы, рискну посоветовать подумать о применеии Loki::SmartPtr. Там, как я уже говорил, есть Small Oject Fixed Allocator, а обёекты класса T, скорее всего имеют малый размер.

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