LINUX.ORG.RU

Сообщения SSN

 

[c++][рефакторинг] Проверка параметров конструктора.

Форум — Development

Столкнулся со следующей задачей.

Есть библиотека, в которой имеется некоторая иерархия классов. В конструкторах этих классов осуществляется проверка передаваемых им параметров и в случае ошибки кидается исключение. Таким образом какая-то общая часть проверок производится в базовых классах, а дополнительные проверки параметров конструктора - в субклассах.

К данной библиотеке написана привязка для python, через которую, собственно, пользователи и работают.

Функции библиотеки очень активно оперируют объектами описанных выше классов (создают/уничтожают). Поэтому в Release-сборке программы все проверки должны отключаться, оставаясь лишь там, где пользователь явно может вызвать конструктор класса, то есть при вызове конструктора класса из python. В Debug-сборке проверки должны присутствовать везде.

Как можно было бы это реализовать без излишнего дублирования кода и чтобы изменения затрагивали меньший объём кода?

SSN ()

[c++][boost::python] Проблема с boost::shared_ptr.

Форум — Development

Здравствуйте.

Возникла проблема, которую удалось локализовать и составить минимальную программу, воспроизводящую её. К сожалению, я не настолько хорошо знаю внутренне устройство boost::python, чтобы самостоятельно разобраться с выявленной ошибкой.

tree.h:

#ifndef _TREE_H_
#define _TREE_H_
#include <boost/smart_ptr.hpp>
#include <map>

class TreeNode;

typedef boost::shared_ptr<TreeNode> TreeNodePtr;

struct EdgeProperties {
    std::size_t weight;

    EdgeProperties();
    EdgeProperties(const std::size_t weight_);
};

typedef std::map<TreeNodePtr, EdgeProperties> EdgesMap;

class TreeNode {
    public:
        typedef std::map<TreeNodePtr, EdgeProperties> ChildNodes;

        const EdgeProperties& edgeProperties(const TreeNodePtr& node) const;
        const EdgesMap& childNodes() const;
        void addChild(const TreeNodePtr& node, const EdgeProperties& properties);
    private:
        EdgesMap children;
};

#endif

tree.cpp:

#include "tree.h"
#include <stdexcept>

EdgeProperties::EdgeProperties():
    weight()
{}

EdgeProperties::EdgeProperties(const std::size_t weight_):
    weight(weight_)
{}

const EdgeProperties& TreeNode::edgeProperties(const TreeNodePtr& node) const {
    EdgesMap::const_iterator pos(children.find(node));
    if (pos == children.end())
        throw std::runtime_error("Not in tree.");
    return pos->second;
}

const EdgesMap& TreeNode::childNodes() const {
    return children;
}

void TreeNode::addChild(const TreeNodePtr& node, const EdgeProperties& properties) {
    children[node] = properties;
}

trees_module.cpp:

#include <boost/python.hpp>
#include "tree.h"

using namespace boost::python;

template <class C>
inline boost::python::dict toDict(const C& v) {
    boost::python::dict d;
    for (typename C::const_iterator i = v.begin(); i != v.end(); ++i)
        d[i->first] = i->second;
    return d;
}

dict getChildNodes(const TreeNode& t) {
    return toDict(t.childNodes());
}

BOOST_PYTHON_MODULE(trees) {

    class_<EdgeProperties>("EdgeProperties", init<>())
        .def(init<const std::size_t>())
        .add_property("weight", &EdgeProperties::weight, &EdgeProperties::weight)
    ;

    class_<TreeNode, TreeNodePtr, boost::noncopyable>("TreeNode", init<>())
        .def("edgeProperties", &TreeNode::edgeProperties, return_internal_reference<>())
        .def("childNodes", &getChildNodes)
        .def("addChild", &TreeNode::addChild)
    ;

}

test.cpp:

#include "tree.h"
#include <iostream>
#include <iomanip>

int main(int, char**) {
    TreeNodePtr n0(new TreeNode());
    TreeNodePtr n1(new TreeNode());

    n0->addChild(n1, EdgeProperties(2));

    const EdgesMap& edges(n0->childNodes());
    std::cout
        << std::boolalpha << (edges.find(n1) != edges.end()) << std::endl
        << n0->edgeProperties(n1).weight << std::endl;

    return 0;
}

test.py:

from trees import *

n0 = TreeNode()
n1 = TreeNode()

n0.addChild(n1, EdgeProperties(2))

print n1 in n0.childNodes()
print n0.edgeProperties(n1).weight

Сборка и запуск:

$ g++ tree.cpp test.cpp -o test
$ g++ -shared -fPIC -lboost_python -lpython2.5 -I /usr/include/python2.5 tree.cpp trees_module.cpp -o trees.so
$ ./test
true
2
$ python test.py
True
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    print n0.edgeProperties(n1)
RuntimeError: Not in tree.
$

Итак, вопрос: почему при вызове edgeProperties из python получается так, что n1 отсутствует в списке дочерних узлов n0, хотя строчкой ранее успешно проверяется, что он там есть? В то же время тест на с++ проходит успешно. Где ошибка?

SSN ()

[benchmarks] Ведение статистики.

Форум — Development

Организованы автоматизированные «ночные» сборки программы для всех сочетаний вариантов сборки (Debug, Release и т. д.), целевых платформ (Linux/Windows) и архитектур (x86, x86_64), компиляторов (GCC, CLang, mingw32). Результаты сборки, прогона тестов, анализа покрытия кода тестами и анализа программы на утечки памяти отсылаются на сервер, на котором поднят CDash.
Помимо тестов имеется также набор benchmark'ов, которые ничего не проверяют, а лишь оценивают работу программы, выдавая набор некоторых величин.
Есть ли какие-нибудь готовые инструменты, подобные CDash, только для benchmark'ов, позволяющие вести статистику по результатам benchmark'ов, в том числе и по нескольким веткам программы одновременно, с возможностью сравнения параметров между ветками и просмотра графиков изменения параметров во времени?

SSN ()

[C++, CMake, MinGW, кросскомпиляция] try ... catch не ловит исключения.

Форум — Development

Здравствуйте!

Программа собирается с помощью CMake. Одна из целевых ОС - Windows. Реализована следующая фабрика:

Base* load(const char* filename) {
	try {return new Derived1(filename);} catch (...) {}
	try {return new Derived2(filename);} catch (...) {}
	try {return new Derived3(filename);} catch (...) {}
	try {return new Derived4(filename);} catch (...) {}
	try {return new Derived5(filename);} catch (...) {}
	try {return new Derived6(filename);} catch (...) {}
	throw std::runtime_error(std::string("Couldn't load file: ") + filename);
}

При кросскомпиляции с помощью MinGW возникает следующая проблема: исключение, поднятое в конструкторе Derived1 не ловится try...catch. При сборке для linux всё работает. Проблема присутствует при всех вариантах CMAKE_BUILD_TYPE. В качестве дополнительных ключей компилятору задавались только: -Wall -Wextra

Debian Oldstable, софт из оф. репозитория.

SSN ()

[C++/OpenMP] Распараллеливание поиска значения в векторе.

Форум — Development

Задача состоит в поиске в очень большом векторе элемента, удовлетворяющего некоторым условиям (проверка достаточно затратна по времени). C OpenMP раньше дела не имел. Реализовал для примера поиск минимального элемента в массиве. Каждый из потоков ищет минимальный элемент в выделенной ему части массива, затем выбирается минимальный элемент из минимальных элементов для каждой части массива.

Компилирую и запускаю:

$ g++ -fopenmp main.cpp

$ ./a.out 1

Time: 1.92

$ ./a.out 2

Time: 2.02

$ ./a.out 3

Time: 2

Почему время поиска не меняется в зависимости от числа потоков? (в системе 2 ядра, top показывает правильное число потоков).

main.cpp:

#include <omp.h>
#include <vector>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <limits>

typedef unsigned int Element;
typedef std::vector<Element> Array;

unsigned int getMinElement(const Array& array, int threadsCount) {
	omp_set_num_threads(threadsCount);
	Array minElements(
		threadsCount,
		std::numeric_limits<Element>::max()
	);
	int size(array.size());
	#pragma omp parallel for schedule(static)
	for (int i = 0; i < size; ++i) {
		int threadNum(omp_get_thread_num());
		if (array[i] <= minElements[threadNum])
			minElements[threadNum] = array[i];
	}
	Element minElement(minElements[0]);
	for (int i = 1; i < minElements.size(); ++i)
		if (minElements[i] < minElement)
			minElement = minElements[i];
	return minElement;
}

int main(int argc, char** argv) {
	Array a;

	for (unsigned int i = 0; i < 100000000; ++i)
		a.push_back(rand());
	
	if (argc < 2)
		exit(1);

	clock_t startTime(clock());
	unsigned int minElement(getMinElement(a, atoi(argv[1])));
	clock_t arrayProcessTime(clock() - startTime);

	std::cout << " Time: "
		<< double(arrayProcessTime) / CLOCKS_PER_SEC << std::endl;

	return 0;
}

SSN ()

[C/C++] Определение расположения файлов ресурсов.

Форум — Development

Есть библиотека и некоторые используемые ею файлы. При сборке и установке данной библиотеки под GNU/linux проблем не возникает, так как каталог установки я указываю ещё на этапе сборки (--prefix), он включается макросом в исходный код и, в следствие этого, библиотеке известно, где будут располагаться ресурсы после установки в систему.

При сборке под ОС Windows с помощью NSIS формируется исполняемый файл-инсталлятор и данный пакет может быть установлен пользователем куда угодно. Как в данном случае в библиотеке определить, где находятся файлы ресурсов?

Пока вижу два пути решения проблемы:

1. Каталог с ресурсами брать из переменной окружения.

2. Искать ресурсы по относительному пути. Но тогда возникает вопрос: как из библиотеки узнать путь к ней?

Есть ли более лучшие/правильные варианты решения данного вопроса?

SSN ()

[C++] Особенности реализации std::vector

Форум — Development

Поведение std::vector при добавлении нового элемента с помошью push_back оказалось для меня неожиданным. Ниже приведён исходный текст программы и результат её работы:


#include <string>
#include <vector>
#include <iostream>

class Foo
{
	public:
		Foo(const std::string& n):
			name(n)
		{ std::cout << "Foo(const std::string&)(" << name << ")" << std::endl; }

		Foo(const Foo& f):
			name(f.name)
		{ std::cout << "Foo(const Foo&)(" << name << ")" << std::endl; }


		~Foo()
		{ std::cout << "~Foo(" << name << ")" << std::endl; }

	private:
		std::string name;
};

int main(int argc, char* argv[])
{
	std::vector<Foo> v;
	
	v.push_back(Foo("a"));
	v.push_back(Foo("b"));
	v.push_back(Foo("c"));

	return 0;
}


Foo(const std::string&)(a)
Foo(const Foo&)(a)
~Foo(a)
Foo(const std::string&)(b)
Foo(const Foo&)(a)
Foo(const Foo&)(b)
~Foo(a)
~Foo(b)
Foo(const std::string&)(c)
Foo(const Foo&)(a)
Foo(const Foo&)(b)
Foo(const Foo&)(c)
~Foo(a)
~Foo(b)
~Foo(c)
~Foo(a)
~Foo(b)
~Foo(c)

Я ожидал, что конструктор будет вызван 6 раз (из них 3 раза копирующий), а получилось, что при добавлении элемента в конец вектора перебираются все его элементы. При этом ещё и создаются их временные копии. В исходниках std::vector сам чёрт ногу сломит. Не подскажите, где можно почитать про особенности реализации данного контейнера. У Страуструпа ничего толкового не нашёл (или просто искал плохо?).

SSN ()

[python] Запуск файла в ассоциированном приложении

Форум — Development

Для запуска файла в ассоциированном с данным типом файла приложении в модуле os под windows доступна функция startfile. Не подскажете, как решить данную задачу в случае linux?

SSN ()

[python] distutils. Установка приложения.

Форум — Development

Каким образом можно с помощью distutils установить приложение на python, состоящее из нескольких модулей, чтобы модули не сваливались в результате куда-нибудь в /usr/share/python-support, где они доступны для импорта кому-угодно, а так, чтобы были доступны только данному приложению? В Debian, например, подобные приложения располагаются в "/usr/lib/имя приложения" и в /usr/bin находится ссылка на исполняемый скрипт в "/usr/lib/имя приложения". В скачанных исходных текстах выбранного наугад подобного пакета обнаружил, что для установки авторы использовали самописный скрипт. :(

В документации на distutils ничего путного не нашел. Функция setup из distutils.core принимает параметры для установки отдельных модулей, пакетов и исполняемых сценариев: py_modules, packages, scripts. Можно, конечно, при сборке deb пакета в rules жонглировать с параметрами install, install_scripts и --install-lib при вызове setup.py, но это некрасиво. Да и приложение будет использоваться как минимум еще в RHEL и Windows.

Если требуемое поведение с помощью distutils реализовать проблематично, то что можно использовать вместо него? (проект целиком на питоне)

SSN ()

gimp на eee

Галерея — Скриншоты

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

Итак. Debian на eee 901, KDE, kwin. Используется принудительное изменение параметров окон (пункт "особые параметры окна" в настройках kwin). Окна приложений (за исключением окон сообщений и т. п.) изначально разворачиваются на весь экран, каждое приложение - на отведённом ему рабочем столе. Для окон GIMP принудительно устанавливаются положение и размер, декорации окон убираются.

На изображении: разбираю и редактирую сделанные ранее снимки.

>>> Просмотр (1024x600, 216 Kb)

SSN ()

Цветная консоль для python

Галерея — Скриншоты

В документации к питону есть примеры того, как можно добавить автодополнение и сохранение истории команд к интерактивной консоли. В дополнение к этому решил ещё эту консоль и раскрасить. Использовал sys.displayhook и sys.excepthook (хотя, может быть, правильнее было бы использовать code.InteractiveConsole?), а также модули token и tokenize.

Рабочая машина. Debian Etch. KDE. Запуск всех необходимых приложений "повешен" на клавиатурные комбинации. Не видны yakuake и katapult.

P.S. На домашнем компьютере Debian Lenny. Пока отлаживал данный сценарий, узнал много нового о разнице между python 2.4 и 2.5.

>>> Просмотр (1680x1050, 350 Kb)

SSN ()

RSS подписка на новые темы