对 iphone operator system 之 我 见

本文探讨了内存管理的重要性,特别是对于C与Objective-C语言。通过实际编程经历分享了如何避免野指针和内存泄露等问题,并强调了理解内存管理机制对于提高程序效率的关键作用。

        内存管理,苹果君给我的第一映像就是对内存的管理。

        速度的响应快慢与内存的管理得失有着密切的关系,有着读写内存权力的C与OC,在一定程度上我们可以做很多事,同时也有很多要关注的事。野指针呀内存泄露呀,计数器在开发过程中也起到了一个中间者的身份,计较“得失”方才安全。

        要说学到的东西还是蛮少的,倒也算入了个门。师傅常说我领你进门,修行得看你个人。感谢(M了个J)李明杰老师(网路视频),虽然课外也找了不少书来看,但手把手的教练编程,还是可以发现不少的问题。比如缺失一个小标点、一个函数缺失实现、一个类名冒号继承等小错误,感悟了也受教了。且行且练多思考。

        最近一直在思考一个问题,思想有多远人就能走多远,能者多责。我不信命,有了一个小小的梦想,希望能恒力戮力势在必行而为之。梦想总是不那么快实现的,即使常常挫败咬着牙齿也能享受苦痛带来给你学习的思考、精神的蜕变、人生的提升。

        生与死,长于斯,而今迈步从头越,又何尝不可?

<think>我们之前讨论过,在`std::map`的`find`函数中,默认情况下并不直接使用`operator==`进行比较,而是通过比较器(默认是`std::less<Key>`,即使用`operator<`)来间接判断相等性:即如果`!(a < b) && !(b < a)`,则认为`a`等于`b`。 但是,用户现在的问题是:**如何在map的find函数中使用operator==进行判断?** 这意味着用户希望改变`std::map`的默认行为,在查找时使用`operator==`来判断键是否相等。这需要我们自定义`std::map`的比较器(comparator),因为默认的比较器并不使用`operator==`。 ### 解决方案:自定义比较器 我们可以通过以下步骤实现: 1. **定义一个比较器(函数对象或函数)**:在这个比较器中,我们首先使用`operator<`来确定顺序(因为`std::map`需要严格弱序来组织元素),但在判断相等时,我们可以显式使用`operator==`。注意,这实际上是不必要的,因为严格弱序已经可以定义相等性。但是,如果我们希望在比较过程中使用`operator==`,可以在比较器中实现。 然而,值得注意的是,`std::map`的比较器只需要定义严格弱序(即提供类似于`operator<`的行为)。在查找时,`find`函数会使用这个比较器来比较键,按照二叉搜索树的规则进行。所以,如果我们想要在比较器中直接使用`operator==`,我们需要重新设计比较器,使其同时满足严格弱序的要求,并且在需要相等判断时使用`operator==`。 但是,这里有一个关键点:比较器本身不应该直接用于判断相等,因为`std::map`的底层实现(红黑树)只使用比较器的“小于”语义。因此,我们无法强制`find`函数使用`operator==`来进行相等判断,除非我们将`operator==`的逻辑融入到比较器的“小于”关系中(这通常是不必要的,而且容易出错)。 不过,有一种间接的方式:我们可以自定义一个比较器,它在比较两个元素时,如果它们相等(用`operator==`判断),则返回`false`(表示不小于),并且也不大于(即另一个比较也返回`false`),这样就会使得两个元素在比较器下相等。但是,这样做的同时,我们还需要保证严格弱序。 实际上,我们通常不会这样做,因为默认方式已经足够。但为了满足用户需求,我们可以尝试如下: ### 自定义比较器示例 假设我们的键类型是`MyKey`,并且我们希望在比较时使用`operator==`来判断相等。我们可以这样定义比较器: ```cpp struct MyComparator { bool operator()(const MyKey& a, const MyKey& b) const { // 如果我们希望使用operator==来判断相等,那么我们需要在比较器中这样处理: // 当a等于b时,返回false(表示a不小于b) // 否则,按照某种顺序(比如使用operator<)返回结果 if (a == b) { // 使用operator== return false; } return a < b; // 注意:这里要求当a==b为假时,a<b和b<a有且只有一个为真 } }; ``` 然后,我们使用这个比较器来实例化`map`: ```cpp std::map<MyKey, ValueType, MyComparator> myMap; ``` 这样,在`myMap.find(key)`时,比较器会被调用,其中就包含了`operator==`的使用。 ### 注意事项 1. **严格弱序要求**:自定义比较器必须满足严格弱序(Strict Weak Ordering)的要求,否则`std::map`的行为是未定义的。严格弱序要求: - 非自反性:`comp(a, a)`必须为`false`。 - 非对称性:如果`comp(a, b)`为`true`,则`comp(b, a)`必须为`false`。 - 传递性:如果`comp(a, b)`为`true`且`comp(b, c)`为`true`,则`comp(a, c)`必须为`true`。 - 等价传递性:如果`a`和`b`等价(即`!comp(a, b) && !comp(b, a)`)并且`b`和`c`等价,则`a`和`c`等价。 在上面的比较器中,我们使用了`operator==`来检查相等,如果相等则返回`false`(表示a不小于b),否则返回`a < b`。这个比较器满足严格弱序吗? - 当`a==b`时,返回`false`,满足非自反性(因为`a`不小于自身)。 - 当`a!=b`时,我们依赖`a<b`。假设`a<b`和`b<a`是互斥的(即`operator<`满足严格弱序),那么非对称性和传递性都可以满足。 - 但是,注意等价关系的定义:在我们的比较器中,`a`和`b`等价当且仅当`!(comp(a, b)) && !(comp(b, a))`。如果`a==b`,那么`comp(a, b)`和`comp(b, a)`都是`false`,所以它们等价。如果`a!=b`,那么`comp(a, b)`就是`a<b`,`comp(b, a)`就是`b<a`。由于`operator<`是严格弱序,所以如果`a`和`b`不可比(即两个比较都是`false`)则它们等价。然而,在我们的情况下,如果`a!=b`,那么`a<b`和`b<a`必有一个为真,所以不会出现两个比较都为假的情况(除非`operator<`在`a!=b`时两个比较都为假,但这是违反严格弱序的)。因此,我们的比较器定义的等价关系就是`a==b`(由`operator==`定义)。 所以,这个比较器满足严格弱序,前提是`operator<`和`operator==`在键类型上相容(即:如果`a==b`为真,则`a<b`和`b<a`都为假;如果`a!=b`,则`a<b`和`b<a`有且只有一个为真)。 2. **潜在问题**:如果`operator==`和`operator<`的定义不一致,可能会导致问题。例如,在某些情况下,两个键`a`和`b`可能满足`a==b`为假,但`a<b`和`b<a`都为假(即不可比),这违反了严格弱序(因为`operator<`必须定义全序或至少严格弱序)。 ### 另一种思路:仅使用`operator==`作为辅助 实际上,我们也可以在自定义比较器中不使用`operator==`,而是让比较器完全基于`operator<`(即默认行为),因为这样已经能够正确判断相等(通过两次比较)。如果用户有特殊需求,比如在自定义比较器中需要用到`operator==`,那么可以按上述方式定义。 ### 总结 - 在`std::map`的`find`函数中,默认不直接使用`operator==`,而是通过比较器的两次比较(`a<b`和`b<a`)来间接判断相等。 - 如果想在查找过程中使用`operator==`,可以通过自定义比较器来实现,在比较器内部调用`operator==`(如上述示例)。 - 自定义比较器必须满足严格弱序,并且要确保`operator==`和`operator<`在键类型上的语义相容。 ### 代码示例 下面是一个完整的示例代码: ```cpp #include <iostream> #include <map> #include <string> class MyKey { public: int id; std::string name; MyKey(int i, const std::string& s) : id(i), name(s) {} // 定义operator== bool operator==(const MyKey& other) const { return id == other.id && name == other.name; } // 定义operator< (如果需要默认比较逻辑,也可以定义) bool operator<(const MyKey& other) const { if (id != other.id) { return id < other.id; } return name < other.name; } }; // 自定义比较器,在比较中使用operator== struct MyComparator { bool operator()(const MyKey& a, const MyKey& b) const { if (a == b) { // 使用operator== return false; } return a < b; // 使用operator< } }; int main() { std::map<MyKey, int, MyComparator> myMap; myMap.insert({{1, "Alice"}, 100}); myMap.insert({{2, "Bob"}, 200}); MyKey key(1, "Alice"); auto it = myMap.find(key); if (it != myMap.end()) { std::cout << "Found: " << it->second << std::endl; } else { std::cout << "Not found" << std::endl; } return 0; } ``` 在这个示例中,我们为`MyKey`定义了`operator==`和`operator<`。然后,我们定义了一个自定义比较器`MyComparator`,它先使用`operator==`判断相等,如果相等则返回`false`(表示a不小于b),否则使用`operator<`。这样,在`find`函数中,就会使用这个比较器,其中包含了对`operator==`的调用。 §§相关问题§§ 1. 如果自定义比较器不满足严格弱序要求,会发生什么? 2. 在`std::map`中,自定义比较器有哪些应用场景? 3. 如何为`std::unordered_map`自定义哈希函数和相等比较函数? </think>在 `std::map` 的 `find` 函数中,**默认不使用 `operator==` 进行判断**,而是通过比较器(默认 `std::less<Key>`)间接定义相等性:两个键 `a` 和 `b` 被视为相等当且仅当 `!(a < b) && !(b < a)`。若需强制使用 `operator==`,必须自定义比较器。以下是具体实现方法: --- ### 步骤 1:定义自定义比较器 创建一个函数对象(仿函数),其中: 1. 在 `operator()` 中调用 `operator==` 判断相等 2. 同时提供严格弱序逻辑(通常基于 `operator<`) ```cpp struct CustomComparator { bool operator()(const KeyType& a, const KeyType& b) const { if (a == b) return false; // 关键点:当相等时返回 false return a < b; // 定义顺序关系 } }; ``` --- ### 步骤 2:在 `std::map` 中使用自定义比较器 将自定义比较器作为模板的第三个参数: ```cpp std::map<KeyType, ValueType, CustomComparator> myMap; ``` --- ### 完整示例(键类型为自定义类) ```cpp #include <iostream> #include <map> #include <string> class MyKey { public: int id; std::string name; // 必须定义 operator== bool operator==(const MyKey& other) const { return id == other.id && name == other.name; } // 必须定义 operator< (用于比较器的基础顺序) bool operator<(const MyKey& other) const { if (id != other.id) return id < other.id; return name < other.name; } }; // 自定义比较器(使用 operator==) struct KeyComparator { bool operator()(const MyKey& a, const MyKey& b) const { if (a == b) return false; // 相等时返回 false return a < b; // 否则按 < 比较 } }; int main() { std::map<MyKey, int, KeyComparator> myMap; myMap.insert({{1, "Alice"}, 100}); myMap.insert({{2, "Bob"}, 200}); MyKey searchKey{1, "Alice"}; auto it = myMap.find(searchKey); // 使用自定义比较器中的 operator== if (it != myMap.end()) { std::cout << "Found: (" << it->first.id << ", " << it->first.name << ") -> " << it->second << "\n"; } else { std::cout << "Not found\n"; } return 0; } ``` --- ### 关键原理说明 1. **比较器的工作机制**: - `find` 调用比较器判断 `key < current_node_key` - 当 `a == b` 时,比较器返回 `false`(即 `a` 不小于 `b`) - 同时树结构会检查 `b < a`(也会返回 `false`) - 此时满足 `!(a<b) && !(b<a)`,判定为相等[^1][^4] 2. **为什么需要 `operator<`**: - `std::map` 底层是红黑树,依赖**严格弱序**组织元素 - 自定义比较器仍需提供顺序逻辑(通常基于 `operator<`)[^4] 3. **重要注意事项**: - 键类型必须同时实现 `operator==` 和 `operator<` - 自定义比较器必须满足严格弱序的三条件(非自反、非对称、传递性) - 若比较器逻辑与 `operator==` 冲突,会导致未定义行为 --- ### 对比默认行为 | **比较方式** | 默认行为 | 自定义使用 `operator==` | |--------------------|----------------------------|------------------------------| | **实现** | 通过两次 `<` 比较间接判断 | 显式调用 `operator==` | | **效率** | 通常更高(避免额外比较) | 可能较低(需额外调用 `==`) | | **适用场景** | 键已支持 `operator<` | 需特殊相等逻辑(如忽略大小写)| > 对于简单需求(如基本类型),默认行为更高效;当需要复杂相等逻辑时,才需自定义比较器[^2][^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值