我想了解为什么会因EXC_BAD_ACCESS
错误而崩溃。它从方法调用返回正常,但随后在[self runMethodThatAssignsError:&error]
上立即崩溃。
我found a similar post here,但它没有解释发生了什么,而且相当陈旧。
- (void)checkError {
NSError *error;
[self runMethodThatAssignsError:&error]; // crashes after returning
NSLog(@"success");
}
- (BOOL)runMethodThatAssignsError:(NSError **)error {
[@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
*error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}];
}];
return NO;
}
答案 0 :(得分:8)
在Instruments中运行示例代码,似乎-[NSArray enumerateObjectsUsingBlock:]
将其块包装在自动释放池中。由于默认情况下NSError **
指针被隐式假设为__autoreleasing
,因此当NSError
对象分配给*error
时,会自动释放-[NSArray enumerateObjectsUsingBlock:]
指针,因此被- (BOOL)runMethodThatAssignsError:(NSError **)error {
__block NSError *_error = nil;
[@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
_error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}];
}];
if (error) *error = _error;
return NO;
}
收获自动释放池。
有两种方法可以解决这个问题。第一个是在块之外使用局部变量,以使ARC在枚举完成之前保留它:
error
或者,您可以将__strong
参数声明为NSError
,这样可以防止- (BOOL)runMethodThatAssignsError:(NSError * __strong *)error {
[@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (error) *error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}];
}];
return NO;
}
首先放入自动释放池中。请注意,只有在此方法的客户端始终使用ARC时才应该这样做,因为否则它可能会导致错误泄漏,因为客户端不希望发布它们,因为这种方法是非常规的。
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
#include <boost/graph/push_relabel_max_flow.hpp>
#include <boost/graph/edmonds_karp_max_flow.hpp>
using namespace boost;
typedef adjacency_list_traits < vecS, vecS, directedS > Traits;
typedef adjacency_list < vecS, vecS, directedS,
property < vertex_name_t, std::string,
property < vertex_index_t, int,
property < vertex_color_t, boost::default_color_type,
property < vertex_distance_t, double,
property < vertex_predecessor_t, Traits::edge_descriptor > > > > >,
property < edge_index_t, int,
property < edge_capacity_t, double,
property < edge_weight_t, double,
property < edge_residual_capacity_t, double,
property < edge_reverse_t, Traits::edge_descriptor > > > > > > Graph;
int main()
{
Graph g;
property_map<Graph, vertex_index_t>::type v = get(vertex_index, g);
property_map<Graph, edge_index_t>::type e = get(edge_index, g);
property_map<Graph, edge_capacity_t>::type cap = get(edge_capacity, g);
property_map<Graph, edge_weight_t>::type cost = get(edge_weight, g);
property_map<Graph, edge_residual_capacity_t>::type rescap = get(edge_residual_capacity, g);
property_map < Graph, edge_reverse_t >::type rev = get(edge_reverse, g);
int nonodes = 4;
for (int i = 0; i < nonodes; i++) {
Traits::vertex_descriptor vd;
vd = add_vertex(g);
assert(v[vd] == i);//(Q1)Here, v[vd] = i; produces an error. Is there any other way to assign integer indices to vertices?
}
Graph::vertex_iterator vertexIt, vertexEnd;
tie(vertexIt, vertexEnd) = vertices(g);
//Create edges
Traits::edge_descriptor edf, edb;//Max flow algorithms seem to want both forward and backward edges. edf is for forward, edb is for backward
//Q2. All of the add_edge() functions below do not seem to add any edges to the graph, leading to a run time error when boykov_kolmogorov_max_flow() is finally called.
edf = (add_edge(*(vertexIt+0), *(vertexIt + 1), g)).first;
edb = (add_edge(*(vertexIt + 1), *(vertexIt + 0), g)).first;
e[edf] = 0;
e[edb] = 1;
cap[edf] = 4;
cap[edb] = 4;
edf = (add_edge(*(vertexIt + 0), *(vertexIt + 2), g)).first;
edb = (add_edge(*(vertexIt + 2), *(vertexIt + 0), g)).first;
e[edf] = 2;
e[edb] = 3;
cap[edf] = 4;
cap[edb] = 4;
edf = (add_edge(*(vertexIt + 1), *(vertexIt + 3), g)).first;
edb = (add_edge(*(vertexIt + 3), *(vertexIt + 1), g)).first;
e[edf] = 4;
e[edb] = 5;
cap[edf] = 4;
cap[edb] = 4;
edf = (add_edge(*(vertexIt + 2), *(vertexIt + 3), g)).first;
edb = (add_edge(*(vertexIt + 3), *(vertexIt + 2), g)).first;
e[edf] = 6;
e[edb] = 7;
cap[edf] = 4;
cap[edb] = 4;
double flow = boykov_kolmogorov_max_flow(g, *(vertexIt + 0), *(vertexIt + 3));
return 0;
}