juce - juce容器

JUCE 框架提供了一系列高效、易用的容器类,用于管理数据集合。这些容器在设计和性能上针对实时音频处理(低延迟、无锁)和跨平台兼容性进行了优化。以下是 JUCE 中常用的容器及其关键用法:


1. juce::Array<T>

  • 用途:动态数组,类似 std::vector,但优化了内存分配策略(适合实时音频场景)。

  • 特点

    • 连续内存存储,支持快速随机访问。

    • 自动内存管理,支持动态扩展。

    • 提供 add()insert()remove()sort() 等方法。

  • 示例

     
    juce::Array<int> numbers;
    numbers.add(10);          // 添加元素
    numbers.add(20, 30);       // 添加多个元素
    numbers.remove(0);        // 删除索引0的元素
    numbers.sort();           // 排序(默认升序)

2. juce::OwnedArray<T>

  • 用途:拥有对象所有权的动态数组,自动管理对象生命周期(类似 std::vector<std::unique_ptr<T>>)。

  • 特点

    • 容器销毁时,自动删除所有元素。

    • 适合管理动态分配的复杂对象(如 UI 组件、音频处理器)。

  • 示例

     
    juce::OwnedArray<juce::Button> buttons;
    buttons.add(new juce::TextButton("Click Me")); // 添加对象
    buttons.clear(); // 自动删除所有按钮对象

3. juce::ReferenceCountedArray<T>

  • 用途:管理引用计数的对象集合(类似 std::vector<std::shared_ptr<T>>)。

  • 特点

    • 元素必须继承自 juce::ReferenceCountedObject

    • 自动跟踪引用计数,无引用时自动释放对象。

  • 示例

     
    class MyObject : public juce::ReferenceCountedObject {
        // ...
    };
    juce::ReferenceCountedArray<MyObject> refArray;
    refArray.add(new MyObject()); // 添加引用计数对象

4. juce::HashMap<Key, Value>

  • 用途:键值对哈希表,类似 std::unordered_map

  • 特点

    • 支持快速查找(O(1) 平均复杂度)。

    • 键需实现 hashCode() 和 operator==

  • 示例

     
    juce::HashMap<juce::String, int> scores;
    scores.set("Alice", 100);     // 插入键值对
    int aliceScore = scores["Alice"]; // 获取值

5. juce::StringArray

  • 用途:专门存储字符串的优化容器。

  • 特点

    • 提供字符串专用的方法(如 joinIntoString()contains())。

    • 支持快速字符串匹配和操作。

  • 示例

     
    juce::StringArray names;
    names.add("John");
    names.add("Jane");
    juce::String joined = names.joinIntoString(", "); // "John, Jane"

6. juce::LinkedListPointer<T>

  • 用途:高效的单链表实现,适合频繁插入/删除的场景。

  • 特点

    • 轻量级,无额外内存开销。

    • 需手动管理节点(通常用于底层数据结构)。

  • 示例

     
    struct Node {
        juce::LinkedListPointer<Node> next;
        int data;
    };
    Node head;
    head.next.insertNext(new Node{ {}, 42 }); // 插入节点

7. juce::Variant

  • 用途:存储任意类型的数据(类似 std::any)。

  • 特点

    • 支持基本类型、字符串、自定义对象。

    • 通过 get<T>() 安全获取值。

  • 示例

     
    juce::Variant value = 42;            // 存储整数
    int num = value.get<int>();          // 获取整数
    value = juce::String("Hello");       // 存储字符串

8. juce::SparseSet

  • 用途:存储不连续整数范围的集合(如选中的 MIDI 音符编号)。

  • 特点

    • 高效存储稀疏数据。

    • 支持范围操作(如 addRange()contains())。

  • 示例

     
    juce::SparseSet selectedNotes;
    selectedNotes.addRange({60, 72}); // 添加音符60到72
    bool isSelected = selectedNotes.contains(64); // 检查是否包含

9. juce::AbstractFifo

  • 用途:无锁环形缓冲区,用于多线程生产者-消费者模式(如音频线程和GUI线程通信)。

  • 特点

    • 线程安全,适合实时音频处理。

    • 需继承并实现 read() 和 write() 方法。

  • 示例

     
    class AudioBufferFifo : public juce::AbstractFifo {
    public:
        AudioBufferFifo(int size) : juce::AbstractFifo(size) {}
        void write(const float* data, int numSamples) { /* 实现写入逻辑 */ }
        void read(float* output, int numSamples) { /* 实现读取逻辑 */ }
    };

10. juce::ValueTree

  • 用途:树形结构数据容器,支持序列化、撤销重做和监听(常用于插件状态管理)。

  • 特点

    • 类似 XML 或 JSON 的结构化数据。

    • 可附加监听器(juce::ValueTree::Listener)监听数据变化。

  • 示例

     
    juce::ValueTree state("PluginState");
    state.setProperty("volume", 0.8, nullptr); // 设置属性
    float volume = state["volume"];            // 获取属性

选择容器的最佳实践

  1. 实时音频线程:优先使用 juce::Array 或 juce::AbstractFifo(避免动态内存分配)。

  2. 对象所有权管理:使用 OwnedArray(自动释放)或 ReferenceCountedArray(共享所有权)。

  3. 键值对存储HashMap 或 juce::NamedValueSet(简单键值对)。

  4. 跨线程通信AbstractFifo + 无锁设计。

  5. 复杂数据模型ValueTree(支持序列化和监听)。


与 STL 容器的对比

JUCE 容器 类似 STL 容器 主要差异
juce::Array std::vector 内存预分配策略更激进,适合实时场景
juce::OwnedArray std::vector<std::unique_ptr> 自动释放对象
juce::HashMap std::unordered_map 接口更简洁,键需实现 hashCode()

代码示例:遍历 juce::Array

juce::Array<int> values {1, 2, 3, 4, 5};

// 传统遍历
for (int i = 0; i < values.size(); ++i) {
    DBG(values[i]);
}

// 范围遍历(C++11)
for (auto& value : values) {
    DBG(value);
}

通过灵活选择容器,可以显著提升 JUCE 应用的性能和代码可维护性。

 

posted @ 2025-05-23 16:30  [BORUTO]  阅读(66)  评论(0)    收藏  举报