2010-07-13 30 views
6

Tôi có mã đệ quy sau đây và tôi nhận được một ngoại lệ stackoverflow. Tôi không thể tìm ra nguyên nhân gốc rễ bởi vì một khi tôi nhận được ngoại lệ, tôi không nhận được cuộc gọi đầy đủ ngăn xếp trong Visual studio.làm thế nào tôi có thể nắm bắt gốc của một ngoại lệ stackoverflow trên mã đệ quy

Ý tưởng là có các nhóm tổ chức hội tụ thành các nhóm "Chính" lớn hơn.

Có ai thấy lỗ hổng trên mã này bên dưới có thể là thủ phạm không?

private Unit GetUnit(Unit organisationalUnit) 
    { 
     if (organisationalUnit.IsMainUnit) 
     { 
      return organisationalUnit;     
     } 

     if (organisationalUnit.Parent == null) 
      return null; 

     return GetUnit(organisationalUnit.Parent); 
    } 

Trả lời

4

Gốc có luôn luôn có Parent == null không? Đã thử kiểm tra

if (organisationalUnit.Parent == organisationalUnit) 
    return null; 

?

+0

do đó, nó là một vấn đề dữ liệu mà cha mẹ của một đơn vị đã được thiết lập như chính nó nhưng đề nghị mã của bạn để kiểm tra này cố định vấn đề của tôi. . – leora

+0

@ooo Tôi rất vui. Lỗi lặp lại chính họ. Giống như lịch sử :-) – Mau

+0

Điều này sẽ không bắt tất cả các trường hợp, một số chu kỳ có thể đi sâu hơn, giống như khi một 'Đơn vị' là ông bà của riêng nó. –

1

Có lý do nào để không mã hóa nó dưới dạng lặp lại không? Bằng cách đó, nó sẽ dễ dàng hơn để thiết lập một giới hạn cứng trên độ sâu của cây tổ chức để bắt dữ liệu xấu (tuần hoàn).

Đệ quy là thú vị, và tối ưu hóa đuôi thậm chí có thể làm cho nó hiệu quả, nhưng ở đây nó có vẻ giống như một cái búa lớn cho một vấn đề nhỏ.

+0

Trong trường hợp này, vấn đề có vẻ như nó có thể là do dữ liệu. –

+0

Thật vậy. Nhưng với giải pháp lặp lại, bạn có thể dễ dàng kiểm tra các chu kỳ dài hơn (ví dụ: bằng cách thêm các nút đã gặp phải vào danh sách hoặc tập hợp một cách rõ ràng). –

5
  1. Bạn có thể có một đơn vị là cha mẹ của chính nó hoặc chặn rằng bạn có thể có chu kỳ của cha mẹ (ví dụ: A-B-C-A). Đó là, vấn đề có thể là với dữ liệu, không phải với mã mỗi lần.
  2. Xác minh rằng getters của IsMainUnitParent không gọi GetUnit.
1

Tôi không biết nhiều về studio trực quan. Nhưng bạn nên kiểm tra sự tái diễn. ví dụ.

private Unit GetUnit(Unit organisationalUnit) 
{ 
     GetUnit(organisationalUnit, new vector()); 
} 

private Unit GetUnit(Unit organisationalUnit,vector x) 
{ 
    if (organisationalUnit.IsMainUnit) 
    { 
     return organisationalUnit;     
    } 

    if (organisationalUnit.Parent == null) 
     return null; 

    x.add(this); 
    if(x.contains(organisationalUnit.Parent)) throw new Exception("recurrent parent"); 
    return GetUnit(organisationalUnit.Parent,x); 
} 
0

Mã có vẻ OK, có thể bạn có một số chu kỳ đóng trong cây Đơn vị? Hãy thử thêm các dòng dấu vết với các giá trị organisationalUnit.GetHashCode, đầu ra dấu vết không bị giới hạn và có thể giúp phát hiện lý do tràn ngăn xếp.

0

Tôi đoán bạn có thể tránh đệ quy bằng cách viết lại này dọc theo dòng của

while(organisationalUnit!=null && !organisationalUnit.IsMainUnit) 
    organisationalUnit=organisationalUnit.Parent; 

return organisationalUnit; 

Tôi hy vọng rằng sẽ giúp.

EDIT: Tôi vừa nhận ra điều này sẽ vẫn không thành công nếu bạn có một số loại phụ thuộc theo chu kỳ.

1

Một cách để làm điều đó là giảm kích thước ngăn xếp để có thể gặp sự cố trước đó.

Bạn có thể làm điều đó bằng cách lãng phí khung khi bắt đầu chương trình, tức là để có dấu vết ngăn xếp như: f_n, f_ (n-1), ..., f_1, chất thải, chất thải, ..., chất thải, như trong (trong C mã giả)

int bị lãng phí = 1;

chất thải (int n, void (* f)()) {if (n> 0) chất thải (n - 1, f) khác f(); bị lãng phí + = 1; }

chính() {chất thải (N, chính); }

trong đó mainprime là chính cũ của bạn và N đủ lớn để đạt được f_1 bạn muốn.

2

Bạn có thể thử cách này để gỡ lỗi tốt hơn. Nó sẽ không ảnh hưởng đến mã sản xuất của bạn.

using System.Diagnostics; 

private Unit GetUnit(Unit organisationalUnit, int depth) 
{ 
    debug.assert(depth < 10, "Reached an unexpected high recursion depth"); 

    if (organisationalUnit.IsMainUnit) 
    { 
     return organisationalUnit;     
    } 

    if (organisationalUnit.Parent == null) 
     return null; 

    return GetUnit(organisationalUnit.Parent, depth + 1); 
} 

private Unit GetUnit(Unit organisationalUnit) 
{ 
    return GetUnit(organisationalUnit.Parent, 0); 
} 

Ngày nghĩ thứ hai ...

Đó là unit rằng bạn có một tham chiếu vòng tròn ở đâu đó.

Bạn có thể thử chuyển một nhóm các nút đã truy cập trước đó và kiểm tra xem bạn có truy cập nút này trước đây hay không.

Điều với đệ quy là bạn phải chắc chắn rằng nó sẽ kết thúc và một tham chiếu vòng tròn đánh dấu là một tình huống mà nó sẽ không kết thúc.

0

Bạn có thể có một chu kỳ trong biểu đồ của mình (xem đó không phải là cây).

Bạn có thể sử dụng mã như thế này để phát hiện nó:

private Unit GetUnit(Unit organisationalUnit) { 
    return GetUnit(organisationalUnit, new HashSet<Unit>()); 
} 

private Unit GetUnit(Unit organisationalUnit, HashSet<Unit> visited) { 
    if (visited.Contains(organisationalUnit)) { 
    throw new Exception("Cycle detected!"); // or just return null if you prefer 
    } 
    visited.Add(organisationalUnit); 

    if (organisationalUnit.IsMainUnit) { 
    return organisationalUnit; 
    } 

    if (organisationalUnit.Parent == null) 
    return null; 

    return GetUnit(organisationalUnit.Parent, visited); 
} 
Các vấn đề liên quan