5

C(++)onstructors

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() метод е по-подходящ тогава.

 

 

 
2

Смятай …

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


TeraFlops, here we come.

 
0

typename Google

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

E Google … можеше просто да споделиш че харесваш C++ meta programming
No need for harsh words, r8 …

 
2

Some cache misses

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 върши работата екстра), а и че за тези неща трябва да се говори в университета, че срамота така завършваме неуки …

 
1

MultiHassle Programming

Posted by savage309 on Oct 15, 2012 in Uncategorized

What CUDA/OpenCL programming is like …

 
1

Git

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


Вижда се, Git има няколко функции, които обикновените клавиатури не предлагат, но има и някои особености при натискане на Return key-a. Пръстите на Линус изглежда са тънки.

 
0

Compile Sort

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;
}

Беше по-трудно, от колкото изглежда :D
Предстоят тестове, колко време отнема и кога започва да се чупи.

 
0

Култура ми Янко

Posted by savage309 on Jul 7, 2012 in Seriously


БТВ и Нова не пожелаха да публикуват снимката, макар да им я пратих.
Но културните мероприятия на министъра с Иво Карамански трябва да ценят. Високо.

 
0

Malus domestica

Posted by savage309 on May 19, 2012 in Uncategorized


Stay hungry.

 
0

Про

Posted by savage309 on Apr 25, 2012 in Uncategorized

Съвсем истинския текст, копиран от dir:

По-рано днес от МВР информираха, че тялото на Бицов е открито на 14 април в дома му. Първоначално се смятало, че става дума за естествена смърт, тъй като дори съдебният лекар не установил следи от насилие. Аутопсията обаче установила, че той е застрелян два пъти в главата.

Този е толкова лекар, колкото аз програмист.

Copyright © 2013 blOgo All rights reserved. Theme by Laptop Geek.