Здравствуйте, кубик, Вы писали:
К>Привет
К>Подскажите чем можно найти такие ошибки копипейста:
К>void * a = func1(); К>if (..){ К> .... К> void * a= func2(); К>} К>delete a;
К>Предполадается что в if блоке надо было "a= func2();"
Здравствуйте, кубик, Вы писали:
К>А статичный анализатор для Visual studio на такое хотя бы обратит внимание? Если да, то какой порекомендуете?
Нет, тупо не видит. Но зато видит встроенный поиск утечек в рантайме:
Detected memory leaks!
Dumping objects ->
d:\c++\console\console.cpp(17) : {68} normal block at 0x009E73D0, 4 bytes long.
Data: < > CD CD CD CD
Object dump complete.
PS: cppcheck видит сразу:
D:\C++\console\console.cpp(19): error: Memory leak: a
Это всё для кода
void* func1()
{
return new int;
}
void* func2()
{
return new int;
}
int main()
{
void * a = func1();
if (a)
{
void * a = func2();
}
delete a;
}
Здравствуйте, jazzer, Вы писали:
J>как насчет переписать на смарт-пойнтеры? J>
J>std::unique_ptr<...> a{func1()};
J>
Вот специально на такие случаи — было бы очень круто иметь переменные с фантомными типами.
Что-то в таком роде:
unassigned<int> x, x0;
foo(x); // static assert failed: доступ к неинициализированной переменной
// собственно, только ради этого и разнесено объявление и инициализацияif(cond)
x = bar();
else
x = buz();
foo(x); // всё равно нельзя, ибо!
x = bar(); // runtime assert failed: повторная инициализация присваиванием (в дебаге придётся тащить булев флажок)
assigned<int> y0; // static assert failed: конструктор без параметров - т.е. не инициализировали
assigned<int> y00(x0); // runtime assert failed: x0 не инициализирован // булев флажок в unassigned<T> подсказывает
assigned<int> y(x), y2(buz());
foo(y); foo(y2);
foo(y00); // проверок не нужно, ибо они были сделаны ранее
Хотя, конечно, сложная ветвистая инициализация нынче делается на лямбдах
int x = [&]()->int {
some local,vars;
eval(local,vars);
if(cond)
return foo(local);
else
return bar(vars);
}();
И достаточно сделать обёртку assigned<T> без дефолтного конструктора. Хошь-нехошь, а инициализируешь.
Здравствуйте, кубик, Вы писали:
К>А статичный анализатор для Visual studio на такое хотя бы обратит внимание? Если да, то какой порекомендуете?
PVS хорош.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>чем haskell/coffee script не устраивает? слишком уж удобно?
Да практически тем же: зигзагообразным порядком чтения.
В коротких формулах удобно писать корнем вперёд
dest = summary( src1, src2, src3 ) -- сразу видно, куда что присваивается
dest = src1 `op` src2 `op` src3 -- а если объединяющая операция примитивная, то и все операнды перед глазами
А в длинных действиях, всё же, предпочтительнее обратная нотация, листьями вперёд
let
f = foo
b = bar
u = buz
in summary f b u
Конвеерные стили того и другого — это
summary $ foo $ bar $ buz x y z
(x,y,z) |> buz |> bar |> foo |> summary
А когда эти два стиля смешиваются, получается адъ.
А смешиваются они из-за синтаксиса, в котором объявление переменной-приёмника должно предшествовать значению
x = (let ..... in .....)
x <- do { ..... }
Было БЫ симпатично, если БЫ была доступна и обратная нотация
runState xyz $ do
foo
bar
buz
return summary
==> x :: Int--> опа, ввели переменную здесь
-- и только с этого места она эксплуатируется
Ладно хаскелл, в нём вся рекурсия неявная, все let суть letrec.
А вот С++, в котором letrec переменных — штатные грабли, или ML, в котором let и letrec живут порознь и тоже могут довести до граблей — там-то позднее объявление пригодилось бы (как мне кажется).
int foo(int* x) { printf("%p",x); return 123; }
int bar(int* x) { printf("%d",*x); return 123; }
int buz(int* x) { *x = 456; return 123; }
int x = foo(&x); // это не страшный летрекint y = bar(&y); // чтение до инициализацииint z = buz(&z); // запись до инициализации (для классов с конструктором это особенно весело)
let fact n = 123 (* заглушка *)in
let fact n = if n<1 then 1 else n * fact (n-1) (* ай, забыли let rec *)in
print_int (fact 5); (* 615, wtf?! *)
Здравствуйте, Кодт, Вы писали:
К>>>>А какой синтаксис красивый сделать для этого добра — загадка.
К>Было БЫ симпатично, если БЫ была доступна и обратная нотация
Здравствуйте, BulatZiganshin, Вы писали:
К>>>>>А какой синтаксис красивый сделать для этого добра — загадка. К>>Было БЫ симпатично, если БЫ была доступна и обратная нотация
BZ>похоже, ты сам и ответил на свой вопрос?
Не ответил, а только помечтал.
Нужно же, чтобы синтаксис был непротиворечивый. А у нас есть и уровень пространства имён, и класса, и внутри шапки стейтментов if/for/while.
Фиг знает, что там повылазит.
Хотя, может быть, пропозал для C++1xz написать. Пускай у Отцов Основателей башка болит.
// префиксное определениеauto x = expression();
some x = {c-style};
some x {c++14-style};
// суффиксное
expression() => auto x;
{ expression(), expression(), expression() } => some y;
чтоб там не полезли неоднозначности, чтоб не показалось, будто expression() или {expression()} — это что-то иное, нежели инициализация определения.
А так,
if(
[]()->auto{ // чёрт с ним, пусть будет обычная лямбда с префиксной аннотацией типа
foo();
bar();
buz();
return new XZ();
}() // и с обычным для лямбды подвалом
=> auto xz
)
{ xz->gogogo(); }
Опять же, какой токен использовать для присваивания? -> наверно, нельзя: для левого операнда это оператор, в отличие от контекста "шапка функции или лямбды". Что-то новое, не являющееся оператором? Как, например, =>
А как быть с множественным определением?
for(int x=1, y=2, z=3; ......)
for(1=>int x, ?!!! после запятой, казалось бы, ещё один int; а после ';' уже выражение условия цикла
Кроме того: если [&]()->auto{......}()=>auto x становится идиомой, (а auto x = [&]()->auto{......}() уже сейчас идиоматично), то, наверно, стоит всё это крючкотворство повыкидывать?
auto x = do{.....};
do{....} => auto x;
Ведь и так понятно, что эта лямбда ничего не защёлкивает, а просто немедленно выполняется, и всё.