Утечка памяти Zig из динамически выделенных записей ArrayList

Я новичок в зигзаге и изучаю его. Поэтому я попытался написать свою собственную функцию разделения юникода (по причинам, пожалуйста, побалуйте меня). Вот:

fn split_utf8(allocator: std.mem.Allocator, in: []const u8, delimiter: []const u8) !std.ArrayList([]const u8) {
    var list = std.ArrayList([]const u8).init(allocator);
    try list.append("");
    var utf8 = (try std.unicode.Utf8View.init(in)).iterator();
    while (utf8.nextCodepointSlice()) |codepoint| {
        if (std.mem.eql(u8, codepoint, delimiter)) {
            try list.append("");
            continue;
        }
        const last: []const u8 = list.pop();
        defer allocator.free(last);
        const new: []const u8 = std.mem.concat(allocator, u8, &[_][]const u8{last, codepoint}) catch "Something went really wrong";
        try list.append(new);
    }
    return list;
}

test "Split test" {
    var expected = std.ArrayList([]const u8).init(std.testing.allocator);
    defer expected.deinit();
    try expected.append("F");
    try expected.append("1");
    try expected.append("100");
    try expected.append("📷click");
    
    const actual = try split_utf8(std.testing.allocator, "F 1 100 📷click", " ");
    defer actual.deinit();
    
    try testing.expectEqual(expected.items.len, actual.items.len);
    // further testing
}

но я всегда получаю сообщение об ошибке, связанное с утечкой адреса, созданного std.mem.concat. Я пробовал следующие вещи:

  • отложить бесплатное новое (сбои)
  • в тесте после утверждения перебирайте фактический и освобождайте каждый элемент (сбой)
  • добавление динамически выделенных пустых строк для инициализации нового «слова» (ничего не изменилось)

Я очень растерян. Я хотел бы знать, как исправить метод Split_utf8? Возможно, в будущем появится список растущих вещей. Спасибо!

«splitAny или SplitSequence или tokenize… оно возвращает мусор» — я думаю, вам стоит сначала разобраться, что не так с вашим кодом, использующим эти функции, прежде чем пытаться углубиться в написание чего-то более сложного.

sigod 12.07.2024 00:01

Хорошо, я понял, что сделал не так; splitAny — это была функция, которую я искал, возможно, я раньше использовал ее неправильно. Остается еще второй вопрос, который имеет совершенно другую природу, а именно управление памятью. Думаю, в будущем мне придется написать массив растущих вещей, есть ли у вас какие-нибудь советы? Также редактируем вопрос, чтобы лучше отразить этот новый вопрос.

lukstru 12.07.2024 00:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не освобождаете отдельные строки, которые есть в списке массива.

Сделайте что-то вроде этого:

const actual = try split_utf8(std.testing.allocator, "F 1 100 📷click", " ");
defer {
    for (actual.items) |str| {
        std.testing.allocator.free(str);
    }
    actual.deinit();
}

Также:

const new: []const u8 = std.mem.concat(allocator, u8, &[_][]const u8{last, codepoint}) catch "Something went really wrong";

catch здесь совершенно неправильный. Просто используйте try. И добавьте оператор errdefer после этой строки. Так:

const new: []const u8 = try std.mem.concat(allocator, u8, &[_][]const u8{last, codepoint});
errdefer allocator.free(new);

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

Другие вопросы по теме