Posted by savage309 on Apr 21, 2013 in
Професионални
Ето една проста С++(98) конструкция, която не рядко се бърка. Хора ползващи Java или друг език в миналото си, и С++ в настоящето си се сблъскват с това :
class Foo {
public:
Foo(){
bar = 42;
printf("Foo()\n");
}
Foo(int) {
buzz = 196;
Foo();
printf("Foo(int); %i %i", bar, buzz);
}
private:
int bar;
int buzz;
};
int main() {
Foo foo(411);
}
На пръв поглед това не трябва да се компилира. Имаме контруктор, който вика друг конструктор (и ползваме C++ < 11). А това не е разрешено в тази версия на езика (макар не всички да го знаят).
За да е тотално объркването обаче, всеки компилатор успява да го компилира без грешки.
Този код работи и не нарушава стандарта.
Не прави обаче съвсем това, което човек би очаквал.
printf("Foo(int); %i %i", bar, buzz); //Foo(int); <undefined> 196
Причината за това е, че Foo() не вика конструктора за обекта, който се конструира във Foo(int), а създава temporary object (без име) !
За по ясно, вместо Foo(); там може да пише int(); … така ще сме създали един int на стека, който както и Foo(); ще спре да съществува след като излезем от scope-а на Foo(int). Може да стане по-ясно, ако добавим деструктор, в който има само printf.
~Foo() {
printf("~Foo()\n");
}
Можем обаче да накараме нещата да сработят .. Ако ползваме placement new, бихме могли да извикаме конструктура върху обекта, който очакваме. Ето така :
Foo(int) {
buzz = 196;
new (this) Foo(); //here be dragons
printf("Foo(int); %i %i", bar, buzz);
}
Показаното по-горе работи (поне в gcc, clang && cl). Но не е съвсем гарантирано, че ще работи навсякъде и винаги. Добрият стар init() метод е по-подходящ тогава.
Posted by savage309 on Nov 22, 2012 in
Професионални

TeraFlops, here we come.
Posted by savage309 on Nov 17, 2012 in
Професионални

E Google … можеше просто да споделиш че харесваш C++ meta programming …
No need for harsh words, r8 …
Posted by savage309 on Nov 3, 2012 in
Професионални
По повод лекцията на Бярне от началото на годината, и едно леко почесване по главата по време на работа преди няколко дни на тема, лоши ли са кеш-мисовете и имат ли те почва у нас, реших днес да проверя от първа ръка
Ето една проста задачка с интересни резултати
Имаме масив с N целочислени числа от 0 до N-1, записани в произволен ред.
Искаме да намерите i-тото от тях, да гo изтрием, но да запазим реда им.
Но вместо i-тото, да вземем да изтрием всички от 0 до N-1 и да ги изтрием едно по-едно .. Питаме се каква структура от данни да ползваме, така че това да се случи най-бързо.
Та, обичайните кандидати .. линеен масив и свързан списък. Свързаният списък изглежда по-обещаващ, вместо да копираме всеки път, само ще меним разни поинтъри.
Правим тестове със std::vector, std::list, custom vector && custom list (кода се намира по-долу)
За да е по-къса цялата лудория, имплементирал съм само методите, които са нужни за демонстрацията (няма деструктури и т.н.). Съобщавайте ако има major грешки в коментарите по-долу.
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <list>
double diffclock(clock_t clock1,clock_t clock2){
double diffticks = clock1 - clock2;
return (diffticks) / CLOCKS_PER_SEC;
}
template <typename T>
class List {
public:
List():first(nullptr), last(nullptr){}
bool empty() const {
return first == nullptr;
}
bool add(T data) {
Node* newNode = new Node(data);
if (first == nullptr) {
last = first = newNode;
} else {
last->next = newNode;
newNode->prev = last;
newNode->next = nullptr;
last = newNode;
}
return true;
}
bool remove(T data) {
Node* temp = first;
while (temp && temp->data != data)
temp = temp->next;
if (!temp) return false;
if (temp == first) {
Node* newFirst = first->next;
delete first;
if (newFirst) newFirst->prev = nullptr;
first = newFirst;
} else if (temp == last) {
Node* newLast = last->prev;
delete last;
if (newLast) newLast->next = nullptr;
last = newLast;
} else {
Node* left = temp->prev;
Node* right = temp->next;
delete temp;
left->next = right;
right->prev = left;
}
return true;
}
private:
struct Node {
Node(T dataRhs):data(dataRhs), prev(nullptr), next(nullptr){}
T data;
Node* prev;
Node* next;
};
Node* first;
Node* last;
};
template <typename T>
class Vector {
public:
Vector():ptr(nullptr), index(0), maxSize(0){}
bool empty() const {
return index == 0;
}
bool reset(int newSize) {
delete[] ptr;
ptr = new T[newSize];
maxSize = newSize;
return true;
}
bool add(T data) {
if (index == maxSize) return false;
ptr[index++] = data;
return true;
}
bool remove(T data) {
int remIndex = -1;
for (int i = 0; i < maxSize; ++i) {
if (ptr[i] == data) {
remIndex = i;
break;
};
}
if (remIndex == -1) return false;
memmove(&ptr[remIndex], &ptr[remIndex + 1], maxSize - remIndex);
--index;
return true;
}
private:
T* ptr;
int index;
int maxSize;
};
const int SIZE = 81000;
template <typename T>
void eraseContainer(T& container) {
for (int i = 0; i < SIZE; ++i)
container.remove(i);
}
template <typename T>
void eraseContainer(std::vector<T>& vec) {
for (int i = 0; i < SIZE; ++i) {
auto iter = std::find(vec.begin(), vec.end(), i);
vec.erase(iter);
}
}
double stdVecTime = 0.0;
double stdListTime = 0.0;
double customVecTime = 0.0;
double customListTime = 0.0;
void test() {
std::vector<int> vecStd;
vecStd.reserve(SIZE);
for (int i = 0; i < SIZE; ++i)
vecStd.push_back(i);
std::random_shuffle(vecStd.begin(), vecStd.end());
using namespace std;
std::list<int> listStd;
for (int i = 0; i < SIZE; ++i)
listStd.push_back(vecStd[i]);
Vector<int> vecCustom;
vecCustom.reset(SIZE);
for (int i = 0; i < SIZE; ++i)
vecCustom.add(vecStd[i]);
List<int> listCustom;
for (int i = 0; i < SIZE; ++i)
listCustom.add(vecStd[i]);
clock_t beginStdVec = clock();
eraseContainer(vecStd);
clock_t endStdVec = clock();
stdVecTime+= double(diffclock(endStdVec,beginStdVec));
if(!vecStd.empty()) printf("Bug in std vector test\n");
clock_t beginStdList = clock();
eraseContainer(listStd);
clock_t endStdList = clock();
stdListTime += double(diffclock(endStdList,beginStdList));
if(!listStd.empty()) printf("Bug in std list test\n");
clock_t beginVec = clock();
eraseContainer(vecCustom);
clock_t endVec = clock();
customVecTime += double(diffclock(endVec,beginVec)) ;
if(!vecCustom.empty()) printf("Bug in custom vector test\n");
clock_t beginList = clock();
eraseContainer(listCustom);
clock_t endList = clock();
customListTime += double(diffclock(endList,beginList));
if(!listCustom.empty()) printf("Bug in custom list test\n");
}
int main(int argc, const char * argv[]) {
const double testTimes = 1.0;
srand((unsigned)time(0));
for (int i = 0; i < testTimes; ++i)
test();
std::cout << "Std vec time:" << stdVecTime / testTimes << std::endl;
std::cout << "Std list time:" << stdListTime / testTimes << std::endl;
std::cout << "Custom vec time:" << customVecTime / testTimes << std::endl;
std::cout << "Custom list time:" << customListTime / testTimes<< std::endl;
return 0;
}
Компилатора е LLVM4.1 с всички оптимизации, процесора – Core2Duo 2.26ghz (P8400), MacOS 10.8.1. Структурите custom vec && custom list всъщност не са от значение, тъй като най-често ни интересуват резултатите от std (написах ги от носталгия, след като завърших хората спряха да ме карат да ги пиша непрекъснато)
Ето и резултатите (lower is better). Замерванията са правени по 3 пъти, показано е средно аритметичното:

По всичко личи, че моя вектор не е много бърз. Това е добре, имплементацията не изглежда много грешна, но пък е бавна. +1 за STL-a 
И понеже никой не харесва таблици, ето ги в арт вариант :

И понеже не се виждат тези в началото заради скалирането, ето ги и тях :

Не ми се мисли, разни езици от високо ниво, пазещи програмистите от “странични ефекти на кода {}”, ползващи за пестене на памет разни линкчета насам-натам колко бързо работят
Изглежда че vector е the silver bullet (и не е вярно, че ако има честа нужда от махане на елементи в средата list-a върши работата екстра), а и че за тези неща трябва да се говори в университета, че срамота така завършваме неуки …
Posted by savage309 on Oct 15, 2012 in
Uncategorized
What CUDA/OpenCL programming is like …

Posted by savage309 on Jul 27, 2012 in
Професионални

Вижда се, Git има няколко функции, които обикновените клавиатури не предлагат, но има и някои особености при натискане на Return key-a. Пръстите на Линус изглежда са тънки.
Posted by savage309 on Jul 15, 2012 in
Професионални
Не че ме бива във функционалното или С++ мета програмиране много, ама спретнах най-накрая и аз един compile time sort. Не претендирам, че е оптимален (нито generic), но май е лесен за четене и разбиране.
#include <iostream>
//all results are saved in ::Value (for type) and ::value (for value)
//gives the smallest in ts...
template<int n, int... ts>
struct Min {
static const int value = n < Min<ts...>::value ? n : Min<ts...>::value;
};
template <int n>
struct Min<n> {
static const int value = n;
};
//holder structure
template<int... vs> struct StaticArray {};
//concatenates v... and u... into an StaticArray
template<typename T1, typename T2>
struct Concat{};
template<int...v, int...u>
struct Concat<StaticArray<v...>, StaticArray<u...>> {
typedef StaticArray<v..., u...> Value;
};
//gives the index of "v" in args...
template<int v, int a, int... args>
struct IndexOf {
static const int value = v == a ? 0 : 1 + IndexOf<v, args...>::value;
};
template <int v, int a>
struct IndexOf<v, a> {
static const int value = v == a ? 0 : -1;
};
//remove element with index "n" from args...
template<int n, int a, int... args>
struct RemoveNth {
typedef StaticArray<a> headValue;
typedef typename RemoveNth< (n - 1), args...>::Value Tail;
typedef typename Concat<headValue, Tail>::Value Value;
};
template<int a>
struct RemoveNth<0, a> {
typedef StaticArray<> headValue;
typedef StaticArray<> Value;
};
template<int a, int... args>
struct RemoveNth<0, a, args...> {
typedef StaticArray<args...> headValue;
typedef StaticArray<args...> Value;
};
//sorts args...
template<typename T1>
struct Sort{};
template<int... args>
struct Sort <StaticArray<args...>> {
//get he min value
typedef Min<args...> min;
//and its index
typedef IndexOf<min::value, args...> index;
//remove the min from the list
typedef typename RemoveNth<index::value, args...>::Value Filtered;
//call recursively for the others
typedef typename Sort<Filtered>::Value TailSorted;
//concat min with the others
typedef typename Concat<StaticArray<min::value>, TailSorted>::Value Value;
};
template<int n>
struct Sort<StaticArray<n>> {
typedef Min<n> min;
typedef StaticArray<n> Value;
};
template<>
struct Sort<StaticArray<>> {
typedef StaticArray<> Value;
};
void printStaticArray(StaticArray<>){ }
template<int v1, int...vs>
void printStaticArray(StaticArray<v1, vs...> m) {
std::cout << v1<< " "; printStaticArray(StaticArray<vs...>());
}
int main (int argc, const char * argv[]) {
printStaticArray(Sort<StaticArray<196, -1, 0, 309, -42, 411>>::Value());
return 0;
}
Беше по-трудно, от колкото изглежда 
Предстоят тестове, колко време отнема и кога започва да се чупи.
Posted by savage309 on Jul 7, 2012 in
Seriously

БТВ и Нова не пожелаха да публикуват снимката, макар да им я пратих.
Но културните мероприятия на министъра с Иво Карамански трябва да ценят. Високо.
Posted by savage309 on May 19, 2012 in
Uncategorized

Stay hungry.
Posted by savage309 on Apr 25, 2012 in
Uncategorized
Съвсем истинския текст, копиран от dir:
По-рано днес от МВР информираха, че тялото на Бицов е открито на 14 април в дома му. Първоначално се смятало, че става дума за естествена смърт, тъй като дори съдебният лекар не установил следи от насилие. Аутопсията обаче установила, че той е застрелян два пъти в главата.
Този е толкова лекар, колкото аз програмист.