Допустим с помощью php создаю сессию:
$_SESSION['user_id'] = 22;
Браузер я так понимаю, создает cookie с id юзера в зашифрованном виде (скажем с помощью
md5). То есть если генерировать с помощью md5 user_id другой (17 к примеру) и заменить
cookie, то получается можно получить доступ к юзеру с id 17?
Или я что-то не понимаю?
Ответы
Ответ 1
У каждой PHP сессии уникальный код который нельзя так просто подобрать, а все данные
сессии хранятся только на сервере этот "уникальный код" который устанавливается в cookie
т.е работает так
Юзер заходит на сайт (при запросе на скачивание html в HTTP заголовках возвращается
запрос на установку в cookie с названием PHPSESSION уникального кода который не зависит
от $_SESSION['user_id'] = 22;)
Потом браузер просто с этим ключом обращается к серверу
Проще говоря можно представить что $_SESSION это файл сессии, user_id ячейка в этом
файле, а 22 это значение ячейки user_id
P.s данные сессии не как нельзя получить на стороне пользователя (если их только
самому не отдать ему к примеру выводом через echo $_SESSION['user_id'];)
Ответ 2
У сервера есть ящик. В ящике лежит user_id = 22.
Сервер на ящик прибивает табличку с какой-нибудь аброкадаброй и хранит у себя все
время сам ящик, никому не дает его.
Затем сервер говорит браузеру: "Запиши, браузер, аброкадабру с таблички этого ящика.
В следующий раз, когда придешь снова, сообщи мне ее и я загляну в ящик с этой табличкой,
чтобы узнать тебя".
Ответ 3
итак:
Допустим, вы раздаете сайт по протоколу http. можете считать, что всех ваших пользователей
уже взломали, админку тоже увели.
этот случай не рассматриваем.
Допустим, вы раздаете сайт по протоколу https
Вы делаете куку, выдаете пользователю. пользователь заходит на сайт, и оставляет
где-нибудь коммент, содержащий js-код. поскольку вы не разбираетесь в куках, то и в
фильтрации js вы тоже не разбираетесь. В простейшем случае, JS-код выдаст в браузер
что-нибудь типа
. У вас XSS-уязвимость. Каждый
посетитель страницы с таким кодом отправит свою куку на сервер атакующего.
Условно говоря, кука (в данном случае, айдишка в куке) прокидывается к атакующему.
Если кука прокинулась к атакущему, простейший скрипт позволит ему при получении куки
автоматически сделать какие-нибудь нехорошие действия, например, зайти под вами в админку,
перезаписать какой-нибудь файл, сохранить его, вы даже и не заметите, что произошло.
Просто какой-то сервер в интернете за 1-2 секунды авторизовался под вами и сделал все
что нужно. Изменил плагин вордпресса, например. А автор заразы в это время спит себе
спокойно. Скрипт работает. А он спит. А у тебя сифилис на сайте. И какой-нибудь вредоносный
код, заражающий пользователей.
В итоге - сервер заражен, пользователи заражены, "и мы в аду и ты горишь, сынок."
Чтобы кука была недоступна для js-кода в браузере, придумали специальный флаг HttpOnly
- почитайте здесь
Это одна из причин, почему некоторые сайты не позволяют заходить одновременно с
двух ip-адресов. Для идентификации пользователя используется пара id+ip.
И именно поэтому, например, какой-нибудь альфа-банк разлогинивает вас автоматически
через, кажется, 10-15 минут неактивности. Пришел к тебе друг, а ты вышел собаку прогулять,
а комп забыл залочить. Находясь в одной и той же подсети, например, можно стащить куку,
и пара cookie/ip с другого компьютера в той же подсети вполне себе сработает без всякого
ip spoofing. (тут я не в курсе, насколько защита от ip spoofing продвинулась за последние
несколько лет)
p.s. поскольку я не специалист по безопасности, а если бы и был, врядли смог бы
выдать полное руководство в ответе, рекомендую вам погуглить и почитать про такие вещи
самому.
p.p.s https-сертификат бесплатно нынче модно получать у https://letsencrypt.org
p.p.s. если вы решите создавать куки самостоятельно, при помощи md5 от id пользователя,
то не решайте так.
Какой-нибудь милый человек посмотрит сколько у вас примерно пользователей, после
этого будет время от времени (в зависимости от количества пользователей) делать запросы
с подходящим md5. Если вы еще приделаете список пользователей онлайн - будет еще легче.
Про соль вы забудете, про перец забудете и в итоге сессия вашего юзера будет md5(1),
md5(2), md5(n)... Можно просто сделать md5(1) = авторизован = творю что хочу. Не балуйтесь
с крипто, не прочитав про него.
Пользуйтесь встроенными механизмами генерации куки от php/почитайте про шифрование
и хэширование.
p.p.p.s
еще бывает очень смешно, когда session_id передают через get-запрос, т.е. session_id
появляется в адресной строке браузера. Если посетителя вашего сайта попросят прислать
ссылку на материал вашего сайта, или он сам выложит ее куда-нибудь, то произойдет авто-логин
Закрыт. Данный вопрос необходимо конкретизировать. Ответы
на него в данный момент не принимаются.
Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он был сосредоточен только на одной проблеме, отредактировав его.
Закрыт 3 года назад.
Как создать полу дугу, создаю дугу с помощью border-bottom:1px solid #000; это полная
дуга, а как сделать ее половинку(или больше половины), идея такая 30% этой дуги желтая,
остальная зеленая.
Создаешь блок и добавляешь стили
.flag {
background-color: #000;
position: relative;
width: 40px;
height: 80px;
}
.flag:before {
content: '';
display: block;
position: absolute;
top: 100%;
border-left: 20px solid #000;
border-right: 20px solid #000;
border-bottom: 20px solid transparent;
}
Ответ 5
Флажок можно разбить на 3 фигуры: 1 прямоуглольник и 2 треугильника.
Прямоугольник можно сделать простым дивом, с красным бэкгрундом.
Сдесь описано как на html+css создавать треугольники.
Раньше было установлено jdk 1.7. Затем, я установил jdk 1.8, а старый удалил. После
чего пропали классы оболочки и запуск происходит с ошибкой:
Error:Cannot run program "C:\Program Files\Java\jdk1.7.0_79\bin\java" (in directory
"C:\Users\ssaan.IdeaIC2016.2\system\compile-server"): CreateProcess error=2, Не удается
найти указанный файл
Где поменять путь на jdk 1.8???
Ответы
Ответ 1
Shift+Ctrl+Alt+S, а там во вкладке Project SDK выбирайте новую версию.
Обычно лежит в папке C:\Program Files\Java\..
Ответ 2
Файл -> Настройки проекта
там укажешь какую версию. по умолчанию автоматом подтянет, а если нет - то создай
через new
Ответ 3
File -> Project Structure -> Project -> Project SDK -> new / edit -> выставляешь
путь до новой джавы
О чем должен говорить комментарий в коде? О том, что происходит в следующем блоке
кода или о том, что должно произойти в результате выполнения этого блока кода? Что
в этом вопросе подсказывает/требует практика?
Ответы
Ответ 1
Хороший комментарий — ненаписанный комментарий. Следует стремиться писать код так,
чтобы комментарии были просто не нужны.
Проблема комментариев в том, что
часто они находятся в одном месте, а помнить о них их нужно в другом
компилятор не может проверить истинность комментария, поэтому при изменении кода
комментарий устаревает
Пройдёмся по часто встречающимся случаям, в которых комментарии излишни.
Если вы хотите прокомментировать, для чего нужна какая-то переменная, выбросьте комментарий,
и измените имя переменной на более подходящее.
int n; // количество страусов
лучше заменить на
int numberOfOstriches;
Если вы хотите сообщить, что выполняется какое-то условие, лучше поставить assert:
// тут pBFG не может быть nullptr-ом, проверка не нужна
pBFG->fire();
лучше заменить на
assert(pBFG);
pBFG->fire();
Если вы описываете в комментарии, что именно делает кусок кода, имеет смысл вместо
этого выделить этот кусок в отдельную функцию, а смысл кода сделать её именем.
// нормализовать вектор скорости
double temp_length = sqrt(velocity.x * velocity.x + velocity.y * velocity.y);
velocity.x /= temp_length;
velocity.y /= temp_length;
лучше заменить на
void Normalize(vector& v)
{
double length = sqrt(v.x * v.x + v.y * v.y);
if (length == 0.0)
throw argument_exception("zero length vector");
v.x /= length;
v.y /= length;
}
Normalize(velocity);
Если вы описываете в комментарии самоочевидные вещи, лучше этот комментарий просто
выкинуть.
// этот класс представляет точку
class Point
{
public int X; // координата X
public int Y; // координата Y
}
ни капли не теряет в читаемости в таком виде:
class Point
{
public int X;
public int Y;
}
(а если бессмысленные комментарии требуются от вас стандартами кодирования, потребуйте
изменения этих стандартов!)
Таким образом, что происходит в участке кода, должно быть по возможности понятно
из самого куска кода. Если это не так — улучшайте его.
Если комментарий представляет собой на деле документацию к вашему коду, тут ничего
не поделаешь, удалять его не нужно.
Те немногие места, где комментарии действительно нужны — описания используемых алгоритмов,
оптимизаций, документация багфиксов и неочевидных решений. Здесь снова-таки старайтесь
писать о том, почему вы делаете так, как делаете. А как именно вы делаете, должно быть
понятно из кода.
Ответ 2
"Ну ты, барин, и задачи ставишь"... (с) К/ф "Формула любви"
К комментариям нет требований. Понимаете, это все равно как спросить - рассказ должен
описывать намерения автора или действия персонажей? Сама постановка странная - что
именно писать в комментарии... А уж различать "что происходит" и "что должно произойти"
- это уж совсем странно.
Вообще-то код нужно писать так, чтоб он сам по себе комментировал, что он делает.
Придумано не мной, но я с этим, в общем-то, согласен. И уж точно не нужно комментировать
в духе "присваиваем переменной сумму двух других" :)
Пишите комментарии так, чтобы вы через год-два могли глянуть на код и разобраться,
что же он делает.
Отдельно я бы выделил комментарии о том, что надо не забыть сделать :)
Если работаете в команде - то работайте так, как решено командой.
Под конец процитирую Саттера:
Не предписывайте стиль комментариев (кроме тех случаев, когда специальный инструментарий
использует их для документирования), но пишите только нужные и полезные комментарии.
Вместо комментариев пишите, где это возможно, код.
Ответ 3
Хорошие комментарии именно в коде (а не перед функциями и т.п.) должны пояснять
зачем этот кусок нужен для решения задачи.
Вполне вероятно, что для понимания этого "зачем", потребуется описать состояние исходных
данных и что получается после выполнения комментируемого кода.
А как именно это реализуется, желательно рассказывать самим кодом.
Закрыт. Этот вопрос необходимо уточнить или дополнить
подробностями. Ответы на него в данный момент не принимаются.
Хотите улучшить этот вопрос? Добавьте больше подробностей
и уточните проблему, отредактировав это сообщение.
Закрыт 2 года назад.
static void Main(string[] args)
{
byte[] data = new byte[] { 8, 8, 3, 8, 5, 6, 7, 8 };
Console.WriteLine(Encoding.UTF8.GetString(data));
Console.ReadLine();
}
С чего бы это?
Ответы
Ответ 1
И правда, с чего бы ей пикать при выводе символа с кодом 7 - BEL (Bell, он же звонок)?
Как еще можно обойти защищенность полей в ооп? кроме дружественных функций
Ответы
Ответ 1
Если говорить действительно о "взломах защиты", т.е. о способах, которые не требуют
кооперации со стороны "взламываемого" класса (т.е. не опираются на изначально заложенные
в класс возможности, типа "друзей", методов, возвращающих указатели на члены и т.п.),
то одна из малоизвестных "дыр", созданных в языке намеренно - это разрешение для явного
инстанциирования шаблона игнорировать ограничения доступа.
В следующем примере мы, не используя никаких "хаков", "друзей" или методов самого
класса, обходим защиту доступа к private методу
#include
class Private {
void private_func() { std::cout << "Pwned!" << std::endl; }
};
using PTR = void (Private::*)();
PTR ptr;
template struct Exploit {
static inline struct D { D() { ::ptr = ptr; } } d;
};
template struct Exploit<&Private::private_func>;
int main() {
(Private().*ptr)();
}
Ключевой момент этой возможности - в разрешении (данном нам разделом 14.7.2/12 стандарта
языка) делать
template struct Exploit<&Private::private_func>;
несмотря на то, что функция Private::private_func является private.
Ответ 2
В общем случае? Или в каких-то конкретных?
Читерство типа
#define private public
считаем недостойным настоящего программиста? :) Копирование описания класса из заголовочного
файла с добавлением в него, например, дружественной функции - тоже?
Есть вариант с созданием своего класса с аналогичным размещением членов в памяти
и reinterpret_cast указателя на один объект в указатель на свой - незаконно, UB, но...
обычно вполне прокатывает :)
Например, через указатель - если тот же друг создаст указатель на что-то закрытое
и вернет его, типа
class X
{
private: int y;
friend int* z(X&x) { return &x.y; };
...
int * p = z(x);
*p = 5;
Или это не годится, хотя дружественная функция используется опосредованно?
Вот вариант со специализацией шаблонной функции. Допустим, есть некий класс.
class X
{
public:
template
void f(const T& t)
{ /* ... */ }
private:
int p;
};
Специализируем эту функцию...
namespace {
struct Y{};
}
template<>
void X::f(const Y&)
{
p = 5;
}
и все. Ловкость рук и никакого мошенничества...
Помогите как заполнить матрицу 3х3 такими же числами в таком же порядке. Умею заполнять
двумерный массив, но вот такие правила заполнения не имею описывать.
Картинка в качестве примера:
Вот так заполняю и вывожу обычно, как это можно исправить?
int[] number = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[,] matrix = new int[3, 3];
int index = 0;
for (int i = 0; i < matrix.GetLength(0); i++)
for (int j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = number[index];
index++;
}
for (int i = 0; i < matrix.GetLength(0); i++)
for (int j = 0; j < matrix.GetLength(1); j++)
if (j == matrix.GetLength(1) - 1)
Console.Write(matrix[i, j].ToString() + "\r\n");
else Console.Write( matrix[i, j].ToString() + "\t");
Ответы
Ответ 1
Например, так:
const int max = 3;
int[,] matrix = new int[max, max];
int curr = 1;
for (int diff = 1 - max; diff <= max - 1; diff++)
{
for (int i = 0; i < max; i++)
{
int j = i - diff;
if (j < 0 || j >= max)
continue;
matrix[i, j] = curr++;
}
}
Проверяем:
for (int i = 0; i < max; i++)
{
for (int j = 0; j < max; j++)
Console.Write(matrix[i, j] + " ");
Console.WriteLine();
}
Результат:
4 2 1
7 5 3
9 8 6
Пояснение: У клеток каждой диагонали разность координат y и x постоянна. Минимальная
разность для «самой верхней» диагонали, в ней лишь клетка (max - 1, 0), разность равна
1 - max. Минимальная разность для «самой нижней» диагонали, в которой клетка (0, max
- 1) равна, разумеется, max - 1. Внешний цикл по этим самым диагоналям. Одна разность
— одна диагональ.
Затем, в каждой диагонали проводим цикл по x-координате (в коде обозначена как i).
Она может быть от 0 до max - 1. Но например для первой диагонали не все x возможны,
т. к. в ней только один элемент. Поэтому мы действуем так: вычисляем x, имея разность
y - x == diff, вычисляем y (в коде j). Проверяем, чтобы y опадало в промежуток от 0
до max - 1.
В каждую найденную клетку записываем следующее число. Текущее число хранится, понятно,
в переменной curr, и увеличивается на единицу после каждой записи в матрицу.
Ответ 2
Как вариант
var matr = new int[3,3];
var cnt = 0;
for(var y=2; y>=-2; y--)
for(var x=0; x<3; x++)
if((y+x) >= 0 && (y+x)<3)
matr[x, y+x] = ++cnt;
проверка
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
Console.Write($"{matr[i, j]} ");
Console.WriteLine();
}
Вывод
4 2 1
7 5 3
9 8 6
Ответ 3
Наивные реализации разобрали до меня, что ж... Если присмотреться, то можно заметить
некоторое сходство искомого порядка заполнения массива с поиском в ширину, воспользуемся
этим и получим такое решение:
class Program
{
static void Main(string[] args) => new Program().Run();
const int dim = 10;
int[,] matrix = new int[dim, dim];
Queue<(int, int)> queue = new Queue<(int, int)>();
void Run()
{
Fill();
Print();
}
void Fill()
{
int index = 0;
queue.Enqueue((dim - 1, 0));
while (queue.Count > 0)
{
var (x, y) = queue.Dequeue();
matrix[x, y] = ++index;
if (x > 0) EnqueueIfNotUsed(x - 1, y);
if (y < dim - 1) EnqueueIfNotUsed(x, y + 1);
}
}
void EnqueueIfNotUsed(int x, int y)
{
if (matrix[x, y] == 0 && !queue.Contains((x, y)))
queue.Enqueue((x, y));
}
void Print()
{
var width = (dim * dim).ToString().Length + 1;
for (int y = 0; y < dim; y++)
{
for (int x = 0; x < dim; x++)
Console.Write(matrix[x, y].ToString().PadLeft(width));
Console.WriteLine();
}
Console.ReadKey();
}
}
Ответ 4
Вот мой вариант. Он любопытен тем, что он реально заполняет змейкой и это особенно
наглядно видно, если во входном массиве не хватает данных для полного заполнения квадрата
ну и под отладкой:
0 0 0 10
0 0 0 0
0 0 0 0
0 0 0 0
0 0 20 10
0 0 0 0
0 0 0 0
0 0 0 0
0 0 20 10
0 0 0 31
0 0 0 0
0 0 0 0
0 44 20 10
0 0 0 31
0 0 0 0
0 0 0 0
0 44 20 10
0 0 55 31
0 0 0 0
0 0 0 0
Сам код:
void Main()
{
const int max = 4;
int[] numbers = { 10, 20, 31, 44, 55, 66, 77, 88, 90, 91, 92, 93, 94, 95, 96, 97 };
var result = this.Putty(max, numbers);
PrettyPrint(result, max);
}
// Define other methods and classes here
public int[,] Putty(int size, int[] numbers)
{
int[,] matrix = new int[size, size];
int x = 0;
int y = size - 1;
int turnAbove = 0;
int turnBelow = 0;
var iter = numbers.GetEnumerator();
while (iter.MoveNext())
{
matrix[x, y] = (int)iter.Current;
PrettyPrint(matrix, size);
x++;
y++;
if (x >= size && y >= size)
{
turnBelow++;
y = 0;
x = turnBelow;
}
else if (y >= size)
{
turnAbove++;
x = 0;
y = size - 1 - turnAbove;
}
else if (x >= size)
{
turnBelow++;
y = 0;
x = turnBelow;
}
}
return matrix;
}
public void PrettyPrint(int[,] matrix, int max)
{
Console.WriteLine();
for (int i = 0; i < max; i++)
{
for (int j = 0; j < max; j++)
Console.Write(matrix[i, j] + " ");
Console.WriteLine();
}
}
Если у вас входные числа идут не по порядку - самое то алгоритм, O(n)
Основа алгоритма - переход от текущей клетки x,y по диагонали через одновременное
инкрементирование x и y.
Далее нужно написать условия определения того, что мы выскочили за край массива.
Я насчитал три варианта вылета: над диагональю, когда вылетели за вертиальную границу;
под диагональю, когда вылетели за горизонтальную границу и на диагонали (вылетели одновременно
за обе границы).
Вероятно, алгоритм можно попробовать оптимизировать (сократить число вспомогательных
переменных или веток условий), оставляю место для творчества.
Так же я не стал учитывать вариант, когда у нас массив полностью заполнен, а входной
IEnumerable ещё не кончился.
Ответ 5
А давайте просто вычислим значение по данным индексам.
Над диагональю это просто: считаем элементы в предыдущих диагоналях (сумма арифметической
прогрессии), и прибавляем номер в текущей диагонали. А чтобы не думать, что там под
диагональю, воспользуемся симметричностью.
Итого:
static int GetValue(int i, int j, int max)
{
if (i <= j)
{
int d = (i - j) + max - 1; // номер диагонали
int s = d * (d + 1) / 2; // сумма предыдущих диагоналей
return s + i + 1; // i = наш номер в диагонали
}
else
{
return max * max + 1 - GetValue(max - 1 - i, max - 1 - j, max);
}
}
Основной код становится тривиальным:
const int max = 3;
int[,] matrix = new int[max, max];
for (int i = 0; i < max; i++)
for (int j = 0; j < max; j++)
matrix[i, j] = GetValue(i, j, max);
Результат, понятно, такой же.
Недавно начал учить Java и в качестве практической задачи нужно написать приложение,
которое должна сравнивать 3 возраста и выдавать результат, кто самый старший, младший
и между ними.
Так же была дана "методичка" в которой изложена суть логики всего этого. Но или я
дурак, или лыжи не едут, но именно такое решение задачи мне просто не дается.
Я просто путаюсь что с чем уже сравнивал и не могу двинуться дальше.
Я не прошу решения этой задачи, просто подскажите - какие еще варианты решения этой
задачи можно использовать ? Метод решения, на котором настаивает учитель мне не подходит.
public class Loader
{
public static void main(String[] args) {
Integer damirAge = 30;
Integer tolanAge = 25;
Integer uraAge = 55;
Integer oldest;
Integer youngest;
Integer middle;
if (damirAge >= tolanAge && damirAge >= uraAge)
oldest = damirAge;
else if (tolanAge >= damirAge && tolanAge >= uraAge)
oldest = tolanAge;
else
oldest = uraAge;
if (damirAge <= tolanAge && damirAge <= uraAge)
youngest = damirAge;
else if (tolanAge <= damirAge && tolanAge <= uraAge)
youngest = tolanAge;
else
youngest = uraAge;
if (damirAge >= tolanAge && damirAge <= uraAge)
middle = damirAge;
else if (tolanAge >= uraAge && tolanAge <= damirAge)
middle = tolanAge;
else
middle = uraAge;
System.out.println("Most young " + youngest);
System.out.println("Middle " + middle);
System.out.println("Most old " + oldest);
}
}
Ответы
Ответ 1
Думаю, что задание предполагало всё-таки освоение логики вложенных операторов if.
По анализу математической подоплёки:
Возможных результатов (перестановок) может быть 6 (если не учитывать случаи равенства).
На получение 6 исходов нужно по меньшей мере 2.58 бита информации, т.е. эта задача
требует в идеале выполнения не более трёх сравнений. Это в данном случае реализуемо
- сравнений будет 2 или 3 (в среднем 2.667):
if A > B:
if A > C:
if B > C:
A B C
else:
A C B
else:
C A B
else:
if B > C:
if C > A:
B C A
else:
B A C
else:
C B A
Ответ 2
Такое странное решение, подходящее для случая именно трёх возрастов:
public static void main(String[] args) {
Integer damirAge = 30;
Integer tolanAge = 25;
Integer uraAge = 55;
Integer oldest = Math.max(Math.max(damirAge, tolanAge), uraAge);
Integer youngest = Math.min(Math.min(damirAge, tolanAge), uraAge);
Integer middle = (damirAge + tolanAge + uraAge) - oldest - youngest;
System.out.println("Most young " + youngest );
System.out.println("Middle " + middle);
System.out.println("Most old " + oldest);
}
Поскольку внутри Math.max/min по сути своей является условным выражением, это решение
можно передалать под вашу задачу с if/else:
public static void main(String[] args) {
Integer damirAge = 30;
Integer tolanAge = 25;
Integer uraAge = 55;
Integer oldest;
Integer youngest;
Integer middle;
if(damirAge > tolanAge){
oldest = damirAge;
} else {
oldest = tolanAge;
}
if(uraAge > oldest){
oldest = uraAge;
}
if(damirAge < tolanAge){
youngest = damirAge;
} else {
youngest = tolanAge;
}
if(uraAge < youngest){
youngest = uraAge;
}
middle = (damirAge + tolanAge + uraAge) - oldest - youngest;
System.out.println("Most young " + youngest );
System.out.println("Middle " + middle);
System.out.println("Most old " + oldest);
}
Но делать нужно конечно через массивы, как ответил @gil9red, на мой взгляд в качестве
учебного задания на if/else можно подобрать гораздо более уместные примеры, чем этот.
Ответ 3
просто подскажите - какие еще варианты решения этой задачи можно
использовать
Условия нужны, но в этой задаче, мне кажется, проще будет другой подход:
Получаем 3 возраста
Помещаем их в коллекцию, например в список
Сортируем список
После сортировки, первым элементом будет самый младший, потом средний и последним старший
Код:
Integer damirAge = 30;
Integer tolanAge = 25;
Integer uraAge = 55;
List ages = Arrays.asList(damirAge, tolanAge, uraAge);
System.out.println(ages); // [30, 25, 55]
// Сортируем
Collections.sort(ages);
System.out.println(ages); // [25, 30, 55]
Integer youngest = ages.get(0);
Integer middle = ages.get(1);
Integer oldest = ages.get(2);
System.out.println("Most young " + youngest);
System.out.println("Middle " + middle);
System.out.println("Most old " + oldest);
Результат:
Most young 25
Middle 30
Most old 55
Ответ 4
Integer damirAge = 30;
Integer tolanAge = 25;
Integer uraAge = 55;
Integer oldest;
Integer youngest;
Integer middle;
if (damirAge >= tolanAge && damirAge >= uraAge){
oldest = damirAge;
if (tolanAge >= uraAge){
middle = tolanAge;
youngest = uraAge;
}else{
middle = uraAge;
youngest = tolanAge;
}
}
else if (tolanAge >= damirAge && tolanAge >= uraAge){
oldest = tolanAge;
if (damirAge >= uraAge){
middle = damirAge;
youngest = uraAge;
}else{
middle = uraAge;
youngest = damirAge;
}
}else{
oldest = uraAge;
if (damirAge >= tolanAge){
middle = damirAge;
youngest = tolanAge;
}else{
middle = tolanAge;
youngest = damirAge;
}
}
Справедливости стоит добавить что данный алгоритм отработает быстрее чем вариант
с сортировкой списка, просто потому что не будем выделять место для списка.
В лучшем случае проведем 3 сравнения Integer, в худшем- 5, мат. ожидание примерно
равно 4.
В разных источниках встречаю разное написание
int *address_0f_x = &longitude;
int* address_0f_x = &longitude;
int * address_0f_x = &longitude;
Компилируются все варианты, мне нравится второй, но к чему всё-таки правильно относить *?
Ответы
Ответ 1
К переменной. Только это не разыменование, а объявление указателя.
Пишите, как хотите, только помните, что
int *p1, *p2;
объявление двух указателей, а
int* p1, p2;
указателя p1 и переменной p2 типа int.
Ответ 2
tl;dr; * при объявлении переменной не является оператором разыменования, а является
частью составного имени типа; имеет смысл использовать исключительно вариант 3.
int * address_0f_x = &longitude;
Исторически в С была симметрия объявления переменных-указателей и их использования.
Объявляя переменную как int *p можно было сказать, что операция *p дает int. Кроме
того, такой синтаксис позволял экономить байты текста в исходниках за счет объявления
нескольких переменных в одной строке.
Однако с появлением С++ и добавлением в него костылей для обозначения ссылок такая
симметрия исчезла. Объявляя переменную как int &p нельзя сказать что операция &p дает
int. А необходимости экономии байтов на исходных текстах программ исчезла, соответственно
объявление нескольких переменных в одной строке стало индикатором маргинального и потенциально
дефективного кода.
Таким образом, имеет смысл разделять объявление переменной на ее тип int * и название
самой переменной p. Так как тип в общем случае не может быть записан вплотную к идентификатору
переменной (например запись intp; будет не корректна), то по соображениям единообразия
имеет смысл не делать исключения для составных типов и всегда отделять тип от наименования
переменной.
По аналогии, так как составляющие типа в общем случае не могут быть записаны вплотную
друг к другу (например запись longlongunsignedint будет некорректна), то по соображениям
единообразия имеет смысл не делать исключения для частей * & и && и всегда разделять
составляющие типа.
Ну а еще лучше по возможности использовать алиасы типов, а не составные типы.
Ответ 3
int* p; Тип все тот же int, а * лишь обьявляет, что переменная это не обьект, а
указатель на тип. Так что выделяется память не для типа, а память, равному одному машинному
слову(независимо от типа), где хранится адрес обьекта. Я бы отнес(мысленно, а не в
записи) знак к переменной, хотя сам имею привычку писать по образцу второго варианта.
Нужно создать переменную следующим образом (псевдокод):
Имя_%номер-пользователя% = значение
Как такое сделать?
Ответы
Ответ 1
В дополнение к существующему ответу.
Динамическое создание переменных сложно поддерживать. И это может быть не безопасно.
Вы можете использовать словари. Словари - это хранилища ключей и значений.
>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'y': 2, 'x': 1, 'z': 3}
>>> dct["y"]
Можно так же использовать имена ключей как переменные
>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'
Для случаев, когда вы думаете о чем-то вроде
var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...
список может быть более подходящим, чем словарь. Список - упорядоченная последовательность
объектов с целочисленными индексами:
l = ['foo', 'bar', 'baz']
print(l[1]) # prints bar, because indices start at 0
l.append('potatoes') # l is now ['foo', 'bar', 'baz', 'potatoes']
Списки могут быть более удобны, чем словари с целыми ключами. Например добавлять
и удалять элементы так удобнее.
Ответ 2
Например, так:
import os
uid = os.getuid()
print(uid) # 1000
try:
print(name_1000)
except NameError as e:
print(e) # name 'name_1000' is not defined
locals()[f'name_{uid}'] = 42
print(name_1000) # 42
Но надо помнить, что динамическое создание переменных - это очень плохая практика.
Скорее всего, задуманное надо реализовывать через ассоциативные структуры данных (словарь,
например).
В зависимости от задачи, переменная может быть создана не только в локальной, но
и в глобальной области видимости с использованием функции globals.
Задаем координаты 4 точек с клавиатуры (x и y).
Как написать условие, которое определяет лежат ли хотя бы три из этих точек на одной
прямой?
Ответы
Ответ 1
Можете воспользоваться уравнением прямой проходящей через две точки:
(x - x_1) / (x_2 - x1) = (y - y_1) / (y_2 - y_1)
Если, уравнение будет выполнятся для какой либо другой точки - она находится на этой
прямой
UPD:
Собственно для трех точек условие будет выглядеть так:
if ((x_3 - x_1) / (x_2 - x_1) == (y_3 - y_1) / (y_2 - y_1)) /*Точки 1, 2, 3 - лежат
на одной прямой */
Ответ 2
Все правильно кроме знака "==". При задании координат точек мы всегда округляем результат
до точности, предусмотренной системой компьютерной алгебры или языком программирования.
Поэтому на практике крайне редко выполняется подобное равенство. Разве что, если взять
точки (1,2); (2,4); (3,6) и т.п. Правильно задаться точностью вычислений Tol и сравнить
с ней разницу результатов:
Tol = 1e-10 //По требованиям задачи или задать как входной параметр
if abs((x_3 - x_1) / (x_2 - x_1) - (y_3 - y_1) / (y_2 - y_1)) <= Tol // Точки лежат
на прямой
Второй вариант, обычно более быстрый:
Tol2 = 1e-20 //Квадрат допустимой погрешности
if ((x_3 - x_1) / (x_2 - x_1) - (y_3 - y_1) / (y_2 - y_1)) ^ 2 <= Tol2 // Точки лежат
на прямой
Можно еще правильнее. Подсчитать коэффициенты уравнения прямой между точками 1 и
2, а далее вычислить "расстояние от точки до прямой". Алгоритм легко гуглится. Если
это расстояние меньше Tol, значит точка лежит на прямой. Однако для большинства задач
это - излишнее усложнение.
Ответ 3
Для целочисленных координат можно использовать формулу:
bool function IsPointsOnLine(int x1, int y1, int x2, int y2, int x3, int y3) {
return (x3 * (y2 - y1) - y3 * (x2 - x1) == x1 * y2 - x2 * y1);
}
или тоже самое, но с кешированием:
void PreIsPointsOnLine(int x1, int y1, int x2, int y2, int& dx, int& dy, int& ds) {
dx = x2 - x1;
dy = y2 - y1;
ds = x1 * y2 - x2 * y1;
}
bool IsPointsOnLine(int dx, int dy, int ds, int x3, int y3) {
return (x3 * dy - y3 * dx == ds)
}
Для четырёх точек можно перебрать четыре условия, поочерёдно исключая одну из точек:
bool function IsPointsOnLine(int x1, int y1, int x2, int y2,
int x3, int y3, int x4, int y4) {
if (IsPointsOnLine(x2, y2, x3, y3, x4, y4) ||
IsPointsOnLine(x1, y1, x3, y3, x4, y4) ||
IsPointsOnLine(x1, y1, x2, y2, x4, y4) ||
IsPointsOnLine(x1, y1, x2, y2, x3, y3) ||) {
return true;
}
return false;
}
Для того, чтобы не было переполнения, числа не должны быть близки к границам целочисленного
типа переменной.
Ответ 4
Вариант с погрешностью предложенный v_mil не работает.
Если кому вдруг понадобится:
Уравнение прямой через две точки:
(x-x1)/(x2-x1) = (y-y1)/(y2-y1)
отсюда:
x*(y2-y1) + x1*(y1-y2) + y*(x2-x1) + y1*(x2-x1) = 0
таким образом для уравнения прямой Ax + By + C = 0 имеем
A = y2 - y1
B = x1 - x2
C = x1 * (y1 - y2) + y1 * (x2 - x1)
Расстояние от точки M (x, y) до прямой считаем по формуле:
d = Math.Abs(A * Mx + B * My + C) / Math.Sqrt(A^2 + B^2)
Вот это расстояние уже можно сравнивать с некой величиной погрешности.
Помогите создать программу, чтобы при нажатии на определенную кнопку, он выдавал
числа по рандому, с нажатием кнопки я разобрался, вот выложил код, а как сделать чтобы
он не прибавлял +5, а просто каждый раз выдавал разные цифры. Я прочитал статьи про
рандом в интернете, но не понял к сожалению, там не на доступном языке и непонятно.
#include
#include
using namespace std;
int main ()
{
int b=0; char c;
while ((c=getch()) !='q')
{
if (c=='a') {
b+=5;
cout << b << endl;
}
}
system ("pause");
return EXIT_SUCCESS;
}
Ответы
Ответ 1
В C++11 есть классы для генерации случайных чисел:
#include
#include
std::default_random_engine rng;
int my_random(int a, int b)
{
std::uniform_int_distribution dist_a_b(a, b);
return dist_a_b(rng);
}
int main()
{
rng.seed(std::random_device()());
std::cout << my_random(0, 42);
}
uniform_int_distribution
Ответ 2
Еще добавлю, что, так как вывод этого числа заключен в цикл, можно использовать случайное
число относительно текущего времени. Это делается примерно так:
подключаем библиотеки
#include и #include
затем генерируем случайное число, предварительно создав переменную текущего момента
времени t:
time_t t;
srand((unsigned) time(&t));
int random = rand()%MAX;
Вот недавно проверил, полностью рабочий код:
#include
#include
#include
using namespace std;
void main(){
int MAX = 10;
time_t t;
srand((unsigned) time(&t));
int random = rand()%MAX;
cout<
#include
#include
using namespace std;
void main(){
int MAX = 10;
int i=0;
srand((unsigned) time(NULL));
while(i!=10){
int random = rand()%MAX;
cout<
Ответ 3
Как получать в С++ случайные числа. Пример.
#include
#include
srand (time (NULL));
int rand_num = rand();
Мне нужно по некой формуле высчитать результат, но это не удается потому что в ней
используется деление числа 25 на число 100.
Все это выглядит примерно так:
double i = 25 / 100; // В этом случае будет выводиться 0, а мне нужно 0.25
В чём здесь проблема?
Ответы
Ответ 1
У Вас в действии int-операнд 25 делится на int-операнд 100. Соответственно и деление
происходит целочисленное. Для ожидаемого Вами результата необходимо хотя бы один из
операндов привести к типу double. Например:
double i = 25 / 100d;
Ответ 2
потому что это инт.
double i = 25.0 / 100;
либо приведите (cast) к double, наверное это делается так:
double i = (double)25 / 100;
Ответ 3
Измени свой код на:
double i = 25 / 100d;
Иначе компилятор считает, что выполняется целочисленное деление, которое в данном
случае вернет 0 вместо 0.25.
Коллеги, вопрос такой:
Как правильно можно узнать количество определенных символов в String/Integer'e?
Допустим есть строка 1110001101011 - мне нужно из нее узнать кол-во единиц или нулей,
как на Java это сделать? Стандартных методов нет...
Ответы
Ответ 1
Наверное самый простой способ будет посимвольный разбор строки и сравнение каждого
элемента отдельно, что-то вроде:
String str = "1100011";
int countNulls=0, countOnes = 0;
for (char element : str.toCharArray()){
if (element == '0') countNulls++;
if (element == '1') countOnes++;
}
Ответ 2
Регулярно не выражаться!
import java.util.*;
import java.lang.*;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
String string = "1110001101011";
Map map = new HashMap();
for ( int i = 0; i < string.length(); i++ ) {
Integer n = map.get( string.charAt(i) );
if ( n == null ) map.put( string.charAt(i), 1 );
else map.put( string.charAt(i), ++n );
}
System.out.println(map);
}
}
Ответ 3
Если эффективно, то цикл. Если штатно - то есть готовый метод - countMatches. Прям
с демками. В общем случае лучше предпочитать готовые библиотечные функции, так как
обычно они уже достаточно хорошо работают. И только если они не удовлетворяют по скорости/качеству
(либо просто нет таких), тогда писать свой велосипед.
Но если это учебное задание, то тогда нужно писать так, как хочет преподаватель,
и не важно, эффективно или нет, так как для некоторых преподавателей важно, что бы
они понимали решение.
Но ещё я в условии заметил слово "Integer". Но в Integer'e нет символов (при желании
их конечно можно найти там, например рассматривая Integer как 4 (или 2) char. Но это
что то не то:)
Ответ 4
данное решение позволяет считать любые символы, у вас есть возможность самому задавать
символы которые нужно посчитать. теоретически должно работать с приемлимой производительностью:
public class CountCharacters {
public static void main(String[] args) {
// two usage examples for provided input string
countCharacters("1110001101011", '0', '1');
countCharacters("1110001101011", new char[] {'0', '1'});
// usage example for custom string
countCharacters("00112233445566778800qwertyuiop[]{}asdfghjkl;'zxcvbnm,./",
'0', '1', 'a', 'b', 'c');
}
private static void countCharacters(String inputString,
char... interestedCharacters) {
final int[] occurences = new int[256];
final char[] array = inputString.toCharArray();
for (final char c : array) {
occurences[c] = occurences[c] + 1;
}
// dump results for characters you are interested in
for (int i = 0; i < interestedCharacters.length; i++) {
System.out.println("found '" + occurences[interestedCharacters[i]]
+ "' occurences for character '" + interestedCharacters[i]
+ "'");
}
System.out.println();
}
}
выводит в консоль:
found '5' occurences for character '0'
found '8' occurences for character '1'
found '5' occurences for character '0'
found '8' occurences for character '1'
found '4' occurences for character '0'
found '2' occurences for character '1'
found '1' occurences for character 'a'
found '1' occurences for character 'b'
found '1' occurences for character 'c'
p.s. минусы, - неоптимальное использование памяти + нет поддержки кодировок. в принцыпе
последнее можно легко исправить
аналогичным образом работает решение для int'ов:
private static int[] ALL_DIGITS = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
protected static void countNumbers(int i) {
countNumbers(i, ALL_DIGITS);
}
protected static void countNumbers(int value, int... digits) {
// number consists of only 10 digits
int[] occurences = new int[10];
// copy value
int x = value;
while (x >= 10) {
int low = x % 10;
occurences[low] = occurences[low] + 1;
x = (x - low) / 10;
}
occurences[x] = occurences[x] + 1;
// dump results for digits you are interested in
for (int i = 0; i < digits.length; i++) {
System.out.println("found '" + occurences[digits[i]]
+ "' occurences for digit '" + digits[i]
+ "'");
}
System.out.println();
}
пример использования:
countNumbers(111000110, 0, 1);
countNumbers(1234567890);
результат:
found '4' occurences for digit '0'
found '5' occurences for digit '1'
found '1' occurences for digit '0'
found '1' occurences for digit '1'
found '1' occurences for digit '2'
found '1' occurences for digit '3'
found '1' occurences for digit '4'
found '1' occurences for digit '5'
found '1' occurences for digit '6'
found '1' occurences for digit '7'
found '1' occurences for digit '8'
found '1' occurences for digit '9'
Ответ 5
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class OneZero {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = "1011110011";
Pattern pattern = Pattern.compile("1");
Matcher matcher = pattern.matcher(s);
int n = 0;
while (matcher.find()) {
System.out.println(matcher.group());
n++;
}
System.out.println("N = " + n);
}
}
Выводит количество единиц в консоль
1
1
1
1
1
1
1
N = 7
Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы на него можно было дать ответ, основанный на фактах и цитатах, отредактировав его.
Закрыт 3 года назад.
Написал прогу, тестовое задание для приема на работу. Код вышел крайне кривой.
Т.е. он-то работает, но малейшая ошибка (при изменении исходных данных или еще что-либо)
разбивает его вдребезги.
Вот собственно хочу спросить совета у бывалых, что лучше делать в таких случаях:
пытаться дописать, довести до ума получившееся "УГ" или все-таки лучше взять и переписать
все на чистовик, абы сверкало и не глючило?
Просто я так подумал, если я так все время буду делать, это ж сколько времени уйдет
даром, если так вот код переписывать всякий раз, когда мне в нем что-то не нравится.
Ответы
Ответ 1
Думаю, что если вы сами не понимаете как ведет себя ваша же программа, то ее обязательно
надо переписать. Тем более, что она - тестовое задание. И не просто переписать, а показать,
на что вы способны по-максимуму.
А за время не беспокойтесь - опыт останется при вас, так что вы даже скорее найдете
работу при качественном выполнении тестового заданий.
Ответ 2
Часто прогеры мечутся между двумя крайностями:
Первая крайность: пытаются заведомо нерабочий код сделать рабочим разнообразными
примочками, мелкими правками и проч. В итоге код запутывается до невозможности
Вторая крайность: перфекционизм - несмотря на то что код рабочий вылизывают код до
потери пульса или же подгоняют под какой-нибудь приличный паттерн. Функционал при этом
остается прежним, а трудозатраты растут.
Я для себя выработал несколько правил:
а. Если код работает - то стараюсь не
вносить мелкие улучшения. Правило:
"Не трогай то что работает!"
б. Код подлежит замене, если его
расширение/модификация привносит
проблемы - это сигнал к пересмотру
кода (даже если код работает).
Правило: "модификации должны быть
гладкими"
в. Если править код, то надо править
конкретно! Правило: "лучше 1
большое изменение, чем 10
маленьких"
Исходя из этого я бы определил, что код автора подлежит замене - согласно правилам
а) и б)
Закрыт. Этот вопрос не по теме. Ответы на него в данный
момент не принимаются.
Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он соответствовал тематике «Stack Overflow на русском».
Закрыт 4 года назад.
Имеется несколько лет опыта с платформой .NET (в основном проекты WinForms на C#).
Сейчас хочу перейти на другую технологию этой же платформы (по причине устаревания
WinForms и сокращения кол-ва проектов под неё), но не могу определиться с выбором:
WPF или ASP.NET. Попробовал их и обе довольно интересны, но не могу понять, что ближе
по душе. Понятно, что разница очевидна - программирование веб-проектов или десктопных,
но я в сомнениях.
А на ваш взгляд, что более интересно и перспективно?
WPF
ASP.NET WebForms
ASP.NET MVC
Ответ прошу прокомментировать.
Заранее благодарен за ответ!
Ответы
Ответ 1
Сам я программирую под WPF. Технология интересная, но требует много знания различных
моментов, очень долго учить. Если бы у меня был шанс сделать свой выбор раньше (а раньше
с интернетом у меня были проблемы), то я все же выбрал ASP.NET MVC или Java. Хотя WPF
тоже ничего, только вакансий на него не так много - следовательно не так востребован.
Но с WPF можно легко пересесть на Silverlight, а лучше если понравился XAML, сразу
начинать с него. С другой стороны если начать с ASP.NET то можно заодно поднять и HTML,
CSS, JavaScript jQuery. Так что выбор очевиден - ASP.NET или (и) CMS какой-нибудь.
Вот я как себе это представляю (сугубо мое видение:) )
ASP.NET MVC -> HTML (CSS) -> SQL -> (jQuery) -> CMS -> Silverlight -> (WPF) - уровень
PHP (MySQL) -> CMS -> jQuery (AJAX) - (просто и) интересно
WPF -> Silverlight -> ASP.NET - эксклюзивно (my)
Objective-C - перспективно
C++ -> ASM32 -> DisASM -> HACK 0101001010 - не советую хД
C++ -> Qt - серьезный С++
C++ -> Android SDK - скучно не будет
Java -> JavaFX - очень хорошая технология
Flash - без комментариев
Unity3D - советую любителям игр
Может что забыл напомните, дополню (и исправлю если что). Жду комментов
Ответ 2
ИМХО более перспективно web. Я бы выбрал ASP.NET MVC. Причины очень просты. В последнее
время намечена тенденция перемещения данных в облака, открывается множество сервисов,
которые предоставляются посредством веб. Рынок настольных приложений, конечно, всё
также популярен, но наибольшим спросом сейчас пользуются именно веб- и мобильные технологии.
Ответ 3
Еще один голос за веб. Мой совет: ASP.NET MVС. И действительно - облачные сервисы
сейчас популярнее коробочных версий. Их проще поддерживать и пользователю ничего не
нужно устанавливать для того, чтобы пользоваться продуктом. Открыл браузер и вуаля)
Вот такой вопрос для любителей С++ in depth.
Приходилось кому-либо в своих проектах определять собственный operator new, operator
new[] и т.п. или встречать в чужом коде? Если да, то с какой целью это было сделано?
Ответы
Ответ 1
Я переопределяю new/delete в расширениях ПО, т.е. в динамических библиотеках, в которых
используется STL и/или библиотеки, наследующие ее модель динамической памяти.
Думаю, проблема "многокучности" известная, когда при инициализации CRT, в каждом
модуле создается своя куча, которой пользуются глобальные методы управления памятью.
Вот, чтобы расширения могли свободно интегрироваться во всех модулях ПО, и переопределяются
операторы new/delete. Для этого, основной модуль экспортирует 2 метода, в которых вызывает
malloc и free, соответственно, а каждое расширение переопределяет свой new/delete,
вызывая в них эти 2 метода.
Получается, что если расширения используют только глобальные new/delete, они все
используют только одну кучу.
А для корректной работы статических объектов, использующих кучу при инициализации,
я перекрываю точку входа в DLL, импортируя эти 2 метода перед инициализацией CRT, после
чего передаю управление встроенной _DllMainCRTStartup. Но есть нюанс, кторый нужно
учесть при такой подстановке: первое, что нужно вызвать в точке входа - __security_init_cookie():
BOOL WINAPI MyDllStartup( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ){
__security_init_cookie();
if( !::MyDllMainPreCRTStartup( hinstDLL, fdwReason, lpReserved ) ){
return FALSE;
}
return _DllMainCRTStartup( hinstDLL, fdwReason, lpReserved );
}
p.s.: вместо malloc и free можно вызывать глобальные new/delete, это уже не принципиально.
Ответ 2
Было дело. Переопределял new для подсчета выделяемой памяти. Помнится тем же способом
пытался ловить утечки памяти. И как-то пробовал писать свой менеджер памяти. В общем
переопределять new скорее для развлечения. В реальных задачах это в общем-то не нужно.
Ответ 3
Я делал такое всего один раз. Нужно было сделать кэш для объектов, о котором бы ничего
не знал код, эти объекты создающий. Код был не мой, и трогать его совершенно не хотелось.
Но надо было как-то пресечь постоянное пересоздание одних и тех же объектов.
В чужом коде видел такое только в книге Александреску. Он там описывал, как сделать
крутой менеджер памяти для маленьких блоков. Это считается?
Ответ 4
В своих. Допустим, есть такая задача: приложение должно захватывать столько памяти,
сколько сказано в конфиге, не больше. Точнее даже так: при старте захатывается кусок
памяти, и всё выделение идёт только внутри него. Потом, в некоторых случаях вешается
сторонний CG, в некоторых - нужна своя отладка выделения/освобождения...
Ответ 5
Я использовал, чтобы некоторые классы размещались в специальном хранилище, которое
чистится при завершении потока. Там в деструкторах не было ничего, кроме уничтожения
зависимых объектов, смысл был в том, чтобы убрать всё это крохоборство из деструкторов
в менеджер памяти, который зачищает всю память оптом.
Опыт скорее не понравился. Много писанины, польза туманна.
На сегодняшний день имею мнение, что интегрировать внутрь класса логику размещения
в памяти бессмысленно. Если хочешь принудить класс к работе через нестандартный менеджер
памяти — закрой конструкторы и создавай экземпляры особой фабрикой. Если классу размещение
не важно, нестандартный менеджер доступен через размещающий конструктор. А встраивание
new/delete в класс — странная херня, смесь бульдога с крокодилом.
Сказанное не относится к переопределению глобальных new/delete, с которыми свой геморрой,
но есть и польза.
Ответ 6
Вообще в проектах не видел. Если не рассматривать только какие-то теоретические примеры
из книг. Зачем это может понадобиться - могу представить. Например, в ситуации, когда
так или иначе стандартный оператор работает неэффективно. Ну, или в целях отладки.
Ведь, действительно, старую версию оператора ведь все равно можно вызвать :-)
Из (полу-)коммерческих видел свой оператор new в MFC.
Ответ 7
Да, приходилось. Но больше в embedded: дефолные реализации звали malloc()/free()
тогда как нужно было использовать аллокатор RTOS (ThreadX). В другом проекте с той
же RTOS был ещё и свой аллокатор с хитрой аллокацией памяти дабы уменьшить фрагментацию
и сократить оверхеды на блочные выделения. Плюс тут же был простенький анализатор мемликов
и логирование аллокаций.
Первый случай - проект сам поднимал, поэтому и сам писал. Второй случай - уже было
сделано.
В своих были только эксперименты, что бы некоторые типы объектов выделялись из специального
пула.
Из популярного, всякие valgrind подменяют вызовы new/malloc/delete/free в целях анализа
утечек, повреждений.
Как организовать невозможность в программе существования нескольких экземпляров одного
класса с одинаковым значением определенного атрибута?
Как называется такой паттерн ООП (если он есть)?
Пишу приложение на JAVA, многопоточное, но примеры интересны на различных языках
программирования (естественно с ООП парадигмой).
Ответы
Ответ 1
В общем случае наиболее подходит под вашу задачу паттерн Factory. В частном случае,
когда разрешен всего 1 объект это классический Singleton. Единственное, я бы не стал
возлагать на паттерн задачу безопасности ибо что Singleton, что Factory ломаются на
раз-два.
Update
Применительно к Java такой способ ведь действительно существует и часто используется
в реальной жизни - например кэширование пула коннектов (например JDBC). Как известно,
коннект ресурс достаточно дорогой и ценный и если по ходу пьесы коннект берется во
многих местах имеет смысл организовать кэширование коннектов с ограничением количества
оных.
Вполне аналогично также и ставится ограничение на количество окон в системе. Да в
том же Android'е надысь писал такую штуку. Ставится корневой класс - прародителей всех
Activity и вперед создавать списочек, контроль все как надо.
Так что надо попроще и без кошачьих завихрений, а то совсем ужо замутили головы boost
commiter, перегрузка операторов...
P.S. Ну вы млин даёте :)
Ответ 2
Эта задачу (если решать ее в общем виде) очень сложно решить хорошо в языках с Garbage
Collector'ами в силу недетерминированности работы последних.
Под хорошим решением подразумевается что-то типа специальной фабрики ObjectFactoryWithAttributeChecking,
в которой хранятся слабые ссылки на объекты выбранных типов, и при попытке создания
нового объекта она проверяет, жив ли прошлый / прошлые или нет.
Понятно, что, в силу недетерминированности GC очень легко получить ситуацию, когда
на объект уже никто не ссылается, но он еще не заколлекчен (и в этот момент фабрика
ObjectFactoryWithAttributeChecking будет вести себя некорректно).
Плохой подход - вводить такую же фабрику с явными методами Create и Dispose - решает
задачу, но сводит на нет преимущества автоматической сборки мусора и крайне неустойчив.
Если calling site в случае такого подхода забудет вызвать Dispose, то ваша фабрика
моментально оказывается в неконсистентном состоянии.
Если задача поставлена из соображений отладки, то самый верный путь решения заключается
в инжектировании своего кода в аллокатор на низком уровне.
.NET, например, допускает такие штуки для решения задач профайлинга, но, в случае
выбора такого подхода каждый кейс нужно рассматривать индивидуально.
В случае языков без сборки мусора (типа C++) вроде как можно реализовать решение
на уровне собственного аллокатора, но сделать это правильно для всех кейсов крайне
нетривиально. Такая задача должна быть по зубам разработчиками уровня boost commiter,
да и то, наверняка, не всем.
Небольшой Update:
Сейчас еще раз перечитал вопрос и, в принципе (если вас устроит такой подход), вы
можете просто сделать фабрику ленивых синглтонов - т.е фабрику с методом getObjectWithSomeConcreteAttribute,
которая будет создавать объект с таким атрибутом только один раз по его первому запросу.
Создание объектов в обход фабрики в таком случае, разумеется, надо запретить.
Другое дело, что это не слишком интересно, если сравнивать с задачей, решения для
которой я предлагаю выше :)
Ответ 3
Есть такой вариант решения "проблемы", недостатки такого подхода очевидны, хотя вариант
имеет право на жизнь (видел в нескольких enterprise продуктах):
public enum TestEnum {
INTEGER {
@Override
public void doAction(Object arg) {
if (arg instanceof Integer) {
System.out.println("int - " + arg);
}
}
},
STRING {
@Override
public void doAction(Object arg) {
if (arg instanceof String) {
System.out.println("str - " + arg);
}
}
},
BOOLEAN {
@Override
public void doAction(Object arg) {
if (arg instanceof Boolean) {
System.out.println("bool - " + arg);
}
}
};
public abstract void doAction(Object arg);
public static void applyAction(Object arg) {
System.out.println("Handling: '" + arg + "'");
for (TestEnum e : values()) {
e.doAction(arg);
}
}
public static void main(String args[]) {
List