Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Вопросы по программированию на C/С++

Автор: Mickey_from_nsk
Дата сообщения: 29.01.2007 07:28
xdude

Цитата:
Товарищи, что-то втыкнуть никак не могу, мозги уже закипают: как написать универсальный темплейт класса, который будет в своём деструкторе освобождать переменную требуемого типа требуемой функцией?

Насколько я помню, это делается объявлением стратегий при создании класса-освободителя. Или явными спецификациями шаблона.
Автор: xdude
Дата сообщения: 29.01.2007 07:46
Mickey_from_nsk

Цитата:
Насколько я помню, это делается объявлением стратегий при создании класса-освободителя. Или явными спецификациями шаблона.

Отсюда поподробней, пожалуйста
Автор: Mickey_from_nsk
Дата сообщения: 29.01.2007 08:17

Цитата:
Отсюда поподробней, пожалуйста

Честно говоря, в твоем примере я не совсем понял постановку задачи. Там есть один объект? Какого типа этот объект? Приведенные тобой функция и метод делают одно и то же? Зачем приведены оба?

По поводу стратегий - создается сец. класс, напр., FreingStrategy с методом freeObject.
Потом от него наследуются стратегии FunctionFreingStrategy, в которой освобождение объекта в методе freeObject идет через вызов функции и MethodFreingStrategy - там - через вызов метода.
Класс освободитель кроме отслеживаемого объекта принимает еще и указатель на стратегию освобождения. В своем деструкторе просто вызывает метод freeObject для данной стратегии.

Автор: xdude
Дата сообщения: 29.01.2007 12:20

Цитата:
Зачем приведены оба?

Да, и функция и метод делают одно и то же, привел ради полноты картины: хочу выяснить, можно ли и в том и в том случае сделать универсальный темплейт высвобождателя.
Насчет стратегии так и не понял: получается, что это не универсальный темплейт, а некий базовый класс, и для каждого нужного мне типа данных и функции-высвобождателя мне нужно писать для него класс-потомок, который будет реализовывать исполнение нужной функции высвобождения в каком-то своём методе (или в деструкторе)?
Автор: distance
Дата сообщения: 29.01.2007 14:02
xdude

Цитата:
Друзья, а есть в STL какая-то функция, которая разбила бы данные в строке, разделенные запятыми (или пробелами, или очередностью символов) на вектор (или список) строк? Типа "test1, test2, test3, test4" на вектор из 4-х строк: "test1", "test2", "test3" и "test4"?

тогда вручную, очевидно...
Код:
template <typename T>
std::vector<std::basic_string<T> > split(std::basic_string<T>& s)
{
typedef std::basic_string<T> S;
std::vector<S> v;

std::basic_stringstream<T> str(s);
std::copy(
std::istream_iterator<S>(str),
std::istream_iterator<S>(),
std::back_inserter(v));
return (v);
}
Автор: xdude
Дата сообщения: 29.01.2007 14:17
distance
Всё время забываю спросить:

Цитата:
CMyThrread pThis = reinterpret_cast<CMyThread>(lpParameter);

Все эти dynamic_cast, reinterpreter_cats и иже с ними - зачем они? Я с С на С++ перешёл, недоучил чего-то, наверное, не понимаю: почему нельзя тупо вот так написать:

Цитата:
CMyThrread *pThis = (CMyThread*)lpParameter;



Добавлено:
Только что посмотрел Бьерн Страуструп. Язык программирования С++. Там описывается только ptr_cast и ref_cast, reinterpret_cast я там не нашёл. Где можно обо всех этих кастах поподробнее почитать, желательно на русском?

Автор: distance
Дата сообщения: 29.01.2007 15:01
xdude
Хм. ptr_cast у Страуструпа? Я должно быть что-то пропустил, этот оператор мне незнаком.

Цитата:
Все эти dynamic_cast, reinterpreter_cats и иже с ними - зачем они? Я с С на С++ перешёл, недоучил чего-то, наверное, не понимаю: почему нельзя тупо вот так написать:

можно и так. главное отличие "старого стиля" что он - один на все случаи, и потенциально небезопасен, а в с++ - есть четкая специализация. например:

Foo* p = new Bar();

Bar* b = (Bar*) p; // если p на самом деле не является потомком от Bar, то ...
p->f(); // ... вот тут нас ждет большой сюрприз

// а это безопасное приведение типов
// в случае когда кастинг невозможен, dynamic_cast вернет NULL
// хотя, imho, если в программе используется dynamic_cast, значит с архитектурой что-то не так...
if (Bar* b = dynamic_cast<Bar*>(p))
{
p->f();
}

reinterpret_cast - это вариант близкий к сишному кастингу.
Автор: xdude
Дата сообщения: 29.01.2007 15:25
distance
Ага, вроде понятно. А это стандарт языка, или чисто мелкосовтовская специфика?


Цитата:
ptr_cast у Страуструпа? Я должно быть что-то пропустил, этот оператор мне незнаком.

Это даже не оператор. Он зачем-то описывает реализцию всего того, что делает dynamic_cast, с помощью функций ptr_cast и ref_cast. Зачем - я сам тольком не знаю, потому что только бегло просмотрел эти главы книги. Тут же он предлагает реализацию проверки типов во время исполнения путем введения в классы дополнительных виртуальных методов. Зачем он это делает - непонятно, есть ведь оператор typeid. аверное, это очень старая книга, написанная ещё для тех компиляторов, которые не поддерживали информацию о типах во время исполнения.

Добавлено:
Блин, народ, такую штуку нарыл:
http://podgoretsky.com/ftp/Docs/Classics/Straustroop/2/Interview.html
Так что все мы тут фигней страдаем, на самом деле
Автор: Qraizer
Дата сообщения: 29.01.2007 20:32
xdude
Не надо воспринимать всякую юмористическую чушь, которую забыли положить в подкаталог Umor, так всерьёз. Ещё раньше появлялись подобные юморески про Unix и plain-С, причём про последний даже жёстче, чем тут про C++ - "Страуструп" тут хоть не обозвал всех C++ программеров дебилами.
Новый стиль операторов кастования - в отличие от старого - не только говорит компилятору, какой тип должен получиться в итоге, но и уточняет, зачем тебе этого захотелось. Посмотри:
Код: const int* pci;
void f(const void*);
/* ... */
f((char*)pci);
Автор: LuckyELF
Дата сообщения: 29.01.2007 20:47
Есть приложение написанное на WinAPI, как получить путь к запускному файлу? т.е. узнать из какой директории запустили программу?
Автор: xdude
Дата сообщения: 29.01.2007 21:42
Qraizer

Цитата:
Там же ещё Ch был.

Ну, я и заменил basic_string на string чтобы это этого самого Ch избавиться Я только с char работаю, wchar_t мне без надобности. В общем, вот что у меня получилось:

Код:
template<class T> inline
T to_num(const std::string &str)
{
    static std::ios_base::iostate st = std::ios_base::goodbit ;
    static std::stringstream ss;
    static std::locale loc("C");
    T ret_val;
std::use_facet<std::num_get<std::string::value_type, typename std::string::const_iterator> >(loc).get(str.begin(), str.end(), ss, st, ret_val);
    return ret_val;
}
Автор: Qraizer
Дата сообщения: 30.01.2007 13:07
В таком случае могу только посочувствовать: у меня отлично работают оба варианта. И typename не нужен, т.к. std::string вполне определённый класс, а не шаблон. Что за компилятор и какая STL? У меня MSVC2003 и STL его же стандартная. Кстати, вместо std::locale loc("C"); юзай std::locale::classic().
Автор: xdude
Дата сообщения: 30.01.2007 17:36

Цитата:
Что за компилятор и какая STL?

MinGW + GCC 3.4.2
Автор: Qraizer
Дата сообщения: 30.01.2007 21:12
RTTI разрешено? По дефолту у MS выключено - нужно специально включать.
Это исключение бросается, если в используемой локали нет нужного фасета. По стандарту он обязан там быть.
Автор: Kostin275
Дата сообщения: 30.01.2007 21:49
нужна помощь спецов написал на с++ программу котороя должна
данные прочитанные из файла и записанные в память вывести на экран
в бинарном виде (16 бит) сечас она выводит как читаетю файл
рпограмма
#include <cstdlib>
#include <iostream>
#include <fstream.h>
#include <string>
//#include <libc.h>

using namespace std;

const int MAX_LINE_LENGTH = 65536;
const int MAX_WORD_LENGTH = 64;
const int var_num = 65536;
//variable *x;
//clause_list *c;


int read_dimacs(char * filename)
{
char line_buffer[MAX_LINE_LENGTH];
char word_buffer[MAX_WORD_LENGTH];
int v[var_num];
int line_num=0;
int i;
long little= 0;
long value =256;
ifstream inp(filename, ios::in);
if (!inp) {
cerr << "Fehler beim Lesen der DIMACS-Datei" << endl;
exit(1);
}
while (inp.getline(line_buffer, MAX_LINE_LENGTH)) {
++line_num;
if (line_buffer[0] == 'c') {
continue;
}
else if (line_buffer[0] == 'p') {

int cl_num;
int arg = sscanf(line_buffer, "p cnf %d %d", &var_num, &cl_num);
if (arg < 2) {
cerr << "Fehler beim Lesen der Anzahl der Variablen und Klauseln"
<< "in der Zeile " << line_num << endl;
exit(3);
}
else

for (int i=0; i < var_num; i++)
{
if (cin>>v[var_num]) continue;
return var_num;
}
for (int i=0; i< var_num; i++)
{
cout << "Die Variablen" << v[i] << "\n";
}
}
for (int i=0; i < var_num; i++)
{
for (int i=0; i<sizeof(v[var_num]); i++)
{
((char*)(&var_num))[i]= i+1;
}
long little= 0;
for (int i=sizeof(v[var_num])-1; i>=0; i--)
{
little = little*256+((unsigned char*)(&value))[i];
v[var_num] = little;
}
}
for (int i=0; i < var_num; i++)
{
if (cin>>v[var_num]) continue;
return var_num;
}

}
return i;

}

void error(char* s, char* s2 = "")
{
cerr << s << ' ' <<s2<< 'n';
exit(1);
}

void read_char(FILE *stream) {
int c;
while( (c=fgetc(stream)) !=EOF)
putchar(c);
}

int main(int argc, char** argv)
{
FILE *datei;
char filename[255];

if(argc < 2) {
printf("Datei");
scanf("%s",filename);
datei = fopen(filename ,"r");
if(datei != NULL)
read_char(datei);
else {
printf("Feller %s\n",filename);
return EXIT_FAILURE;
}
}
else {
datei=fopen(argv[1],"r");
if(datei != NULL)
read_char(datei);
else {
printf(" %s nicht auf!\n",argv[1]);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}



файл с
Автор: Lyrik
Дата сообщения: 30.01.2007 23:39
Kostin275
А в чем конкретно проблема вывода в бинарном виде?
И что значит:
Цитата:
файл с
???
Автор: royt
Дата сообщения: 01.02.2007 11:54
Kostin275
Вы видимо не до конца написали сообщение. Сформулируйте чего хотите, и что за файл.

LuckyELF
Цитата:
Есть приложение написанное на WinAPI, как получить путь к запускному файлу? т.е. узнать из какой директории запустили программу?
Если под "запускным файлом" имеется ввиду имя файла процесса - то выше написали. Но, вообще говоря, путь к этому файлу и директория, из которой запустили процесс (текущая директория) могут быть разными.
Автор: LuckyELF
Дата сообщения: 01.02.2007 16:52
Спасибо с путем все нормально, сделал как ту написали и все получилось.

зато появились новые вопрсы:
1. что такое WCHAR? чем он отличается от char? зачем он ваще нужен.
наткнулся в одной статье на такую вешь

//имя файла. Не забывайте символ L (так надо).
WCHAR wstrFileName[MAX_PATH] = L"Windows XP Startup.wav";

зачем там нужен это символ L?

2. как правильно конвертировать строку WCHAR в char.

Добавлено:

Цитата:
Но, вообще говоря, путь к этому файлу и директория, из которой запустили процесс (текущая директория) могут быть разными.


что это значит?
вот например у меня есть приложение my_app.exe, которое лежит в d:\prj\my_app\, и когда я его запускаю получается такая строчка d:\prj\my_app\my_app.exe, вот ее я и хотел получить.
а о чем вы я не знаю
Автор: Abs62
Дата сообщения: 01.02.2007 18:30
LuckyELF

Цитата:
что такое WCHAR? чем он отличается от char?

CHAR - однобайтовые символы, WCHAR - двухбайтовые (Unicode).

Цитата:
зачем там нужен это символ L?

Чтобы сообщить компилятору, что это юникодная строка.

Цитата:
как правильно конвертировать строку WCHAR в char.

WideCharToMultiByte
Автор: Qraizer
Дата сообщения: 01.02.2007 18:39
WCHAR - это wide char, то бишь юникововый символ. WCHAR для универсальности. Для компиляторов, не поддерживающих wchar_t, может быть определён как typedef unsigned short WCHAR;, для поддерживающих - typedef wchar_t WCHAR; Твоя программа становится независимой от старых компиляторов, если ты будешь использовать WCHAR.
"some string" - const char[];
L"some string" - const wchar_t[];
В общем случае wchar_t[] не может быть преобразован в char[], т.к. диапазон широких символов шире обычных. Если никаких там иероглифов, диакритических знаков, математических символов и тому подобной лабуды не встретится, то однозначное преобразование возможно. Для кастования туда/обратно есть C-функции mbstowcs() и wcstombs(). Но советую посмотреть WinAPI-функции MultiByteToWideChar() и WideCharToMultiByte(). Они гораздо гибче.
Автор: PavelO
Дата сообщения: 02.02.2007 22:31
Объясните пожалуйста почему выдает ошибку: Call to undefined function 'delay'
Код такой:
#include <time.h>
#include <stdio.h>
#include <dos.h>

int main(void)
{
clock_t start, end;
start = clock();

delay(2000);

end = clock();
printf("The time was: %f\n", (end - start) / CLK_TCK);

return 0;
}
Автор: rain87
Дата сообщения: 02.02.2007 23:04
PavelO
чем компилируешь?
если компилить досовским 3.1, то всё компилится
а если вижуалом, то код нужен такой
Код: #include <time.h>
#include <stdio.h>
#include <windows.h>

int main(void)
{
clock_t start, end;
start = clock();

Sleep(2000);

end = clock();
printf("The time was: %f\n", (float)(end - start) / CLK_TCK);

return 0;
}
Автор: Kostin275
Дата сообщения: 02.02.2007 23:48
royt
прошу извенить сразу не ответил хотел сам найти ошибку
программа должна брать данные из файла считывать их
записывать в память а затем выдовать на экран данные из этой
памяти в двоичном коде 16 бит это часть из большой программы,
котороя должна брать данные из файла и выводить на сом порт компьютера
при этом 1 бит должен быть 1 или 0 и я разбил это задание на две части
думал так будет легче файл с -это файл с данными которые запрашивает программа при запуске
Автор: veronica b
Дата сообщения: 03.02.2007 10:16
rain87

Цитата:
чуднО

Могу попытатся вам объянить. Функция delay(...) - зто чисто ДОСовская функция, работающая от таймера, обновляющегося с частотой 50Гц. Её точность зависит от качества электросети. Функция Sleep(...) работает по другому, она синхронизируется от более точного таймера. На указанное в ее аргументе время в милисекундах, она уберает поток из очереди потоков, после, как время истекло, она не отправляет поток на выполнение, а только ставит его в очередь.
Разница 2.000000 - 1.978022 равно 0.0220. Так как 1.978022 измеряется с точность +- 0.01, то округлим и получим 1.98. Все в допуске.
Автор: Abs62
Дата сообщения: 03.02.2007 11:22

Цитата:
Функция delay(...) - зто чисто ДОСовская функция, работающая от таймера, обновляющегося с частотой 50Гц. Её точность зависит от качества электросети.

А в ноутбуках, наверно специальный преобразователь 12->220 встраивают, чтобы таймер работал, да?
И чего только не узнаешь на форуме...
Автор: rain87
Дата сообщения: 03.02.2007 13:08
про электросеть это конечно интересно а как проблема с электросетью решается в вмваре?

в общем поэкспериментировал ещё слегка. прога выдаёт 2 варианта:
Цитата:
The time was: 2.032967

Цитата:
The time was: 1.978022
разница 2.032967-1.978022=0.054945
теперь - финт ушами 1/0.05494=18.200018200018200018200018200018
с учётом погрешностей проги при выводе, 18.2
а к чему всё это - к тому, что у меня какое-то смутное воспоминание, что когда комп выключен, процессор от батарейки считает время каждые 1/18.2 секунд. т.е. минимальный тик - приблизительно 0.055 секунд.
под вынём это дело, видимо как-то поправлено. может у винды свой счётчик времени, независимый от аппаратного

Добавлено:
поправил точность
Цитата:
The time was: 1.97802197802197810000

Цитата:
The time was: 2.03296703296703285000
2.03296703296703285000-1.97802197802197810000=0.05494505494505475;
1/0.05494505494505475=18,200000000000064610000000000229
всё равно не хватает точности но уже ближе

Добавлено:
ещё одно замечание 1.97802197802197810000/0.05494505494505475=36,000000000000129220000000000459
Автор: Abs62
Дата сообщения: 03.02.2007 13:52
rain87

Цитата:
а к чему всё это - к тому, что у меня какое-то смутное воспоминание, что когда комп выключен, процессор от батарейки считает время каждые 1/18.2 секунд. т.е. минимальный тик - приблизительно 0.055 секунд.

Не процессор, и не только когда выключен. Трёхканальный таймер. Насколько я помню, первый канал - рефреш памяти, второй - спикер, третий - часы (вот он как раз и выдаёт импульсы каждые 55 мс).

Цитата:
под вынём это дело, видимо как-то поправлено. может у винды свой счётчик времени, независимый от аппаратного

Sleep отрабатывает планировщик процессов - у него свой таймер, да. А вот таймеры, создаваемые SetTimer, используют вышеупомянутый таймер с дискретностью 55 мс.
Автор: rain87
Дата сообщения: 03.02.2007 14:00
ну насчёт процессора - да, тупо сказал. просто не знал, как обозвать этот таймер
в общем, разобрались. и то хлеб
Автор: veronica b
Дата сообщения: 03.02.2007 16:10
Abs62
rain87

Цитата:

#include <dos.h>
void delay(unsigned milliseconds);

Description

With a call to delay, the current program is suspended from execution for the number of milliseconds specified by the argument milliseconds. It is no longer necessary to make a calibration call to delay before using it. delay is accurate to a millisecond.

В 1996 году мне нужно было на ПК сформировать ипульс, импульс проверялся осцилографом. При пощи этой функции удавалось сформировать импульсы с дискретой в 20 мс. Естественно, можно было сделать вывод о синхронизации сетью.
Автор: Qraizer
Дата сообщения: 03.02.2007 17:12
Ну вот, сразу видно, кто системным программированием под DOS занимался .
Этот самый аппаратный таймер вообще-то программируется. На него подаётся кварц с немного меньшей 2МГц частотой (сомневаюсь, чтобы частота сети тут играла какую-то роль), и он тупо считает импульсы. Через определённое количество импульсов он формирует активный сигнал на своём выходе. Первый канал таймера BIOSом программировался на режим периодического одновибратора (вроде) и (тут уже BIOS, конечно, ни причём) заводится на первый (нулевой?) вход контроллера прерываний. Так и получается IRQ0. Второй - до эпохи AT использовался для формирования запроса DR0 контроллеру прямого доступа к памяти, который в свою очередь просто пробегал по памяти, формируя фиктивные операции доступа, чего вполне хватало для обеспечения её рефреша. BIOSом этот канал таймера программировался в режим периодического аппаратно перезапускаемого одновибратора. Третий канал - через простую логику подавался на спикер, и программировался в режим генератора прямоугольных импульсов.
"Определённое количество импульсов" программируется путём задания делителя. Делитель является 16-битным числом, и BIOS программила первый канал таймера максимальным его значением, чтобы поменьше напрягать процессор прерываниями. Так и получалась частота 18,2 раза в секунду. Этого вполне хватало для подсчёта количества переполнений, то бишь системного времени. При желании можно было получить текущее время с точностью до полумикросекунд, если к текущему "счётчику переполнений" прибавить текущее значение счётчика самого первого канала таймера.
Многие игрушки уменьшали значение делителя, т.к. им были нужны более частые IRQ. Например, чтобы играть MIDишки, нужно по меньшей мере в 5 раз ускорить IRQ. Win3x тоже использовала квант времени порядка 20мсек. Библиотека MMSYSTEM и драйверы уровня ядра могли переопределить его вплоть до 1мсек. Конечно, можно и прямо запрограмить порты таймера, но Winде от этого сильно плохело.
Вот вам и разница в точности таймеров.

Страницы: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193

Предыдущая тема: не знаю как назвать тему :-)


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.