|
29 | 29 | #include <memory> // unique_ptr |
30 | 30 | #include <string> // string, stoi, to_string |
31 | 31 | #include <utility> // declval, forward, move, pair, swap |
| 32 | +#ifdef _MSC_VER |
| 33 | + #include <vcruntime.h> // _HAS_EXCEPTIONS |
| 34 | +#endif |
32 | 35 | #include <vector> // vector |
33 | 36 |
|
34 | 37 | #include <nlohmann/adl_serializer.hpp> |
@@ -568,51 +571,65 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec |
568 | 571 | } |
569 | 572 | if (t == value_t::array || t == value_t::object) |
570 | 573 | { |
571 | | - // flatten the current json_value to a heap-allocated stack |
572 | | - std::vector<basic_json> stack; |
573 | | - |
574 | | - // move the top-level items to stack |
575 | | - if (t == value_t::array) |
576 | | - { |
577 | | - stack.reserve(array->size()); |
578 | | - std::move(array->begin(), array->end(), std::back_inserter(stack)); |
579 | | - } |
580 | | - else |
581 | | - { |
582 | | - stack.reserve(object->size()); |
583 | | - for (auto&& it : *object) |
584 | | - { |
585 | | - stack.push_back(std::move(it.second)); |
586 | | - } |
587 | | - } |
588 | | - |
589 | | - while (!stack.empty()) |
| 574 | +#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_HAS_EXCEPTIONS) |
| 575 | + try |
590 | 576 | { |
591 | | - // move the last item to local variable to be processed |
592 | | - basic_json current_item(std::move(stack.back())); |
593 | | - stack.pop_back(); |
| 577 | +#endif |
| 578 | + // flatten the current json_value to a heap-allocated stack |
| 579 | + std::vector<basic_json, allocator_type> stack; |
594 | 580 |
|
595 | | - // if current_item is array/object, move |
596 | | - // its children to the stack to be processed later |
597 | | - if (current_item.is_array()) |
| 581 | + // move the top-level items to stack |
| 582 | + if (t == value_t::array) |
598 | 583 | { |
599 | | - std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack)); |
600 | | - |
601 | | - current_item.m_data.m_value.array->clear(); |
| 584 | + stack.reserve(array->size()); |
| 585 | + std::move(array->begin(), array->end(), std::back_inserter(stack)); |
602 | 586 | } |
603 | | - else if (current_item.is_object()) |
| 587 | + else |
604 | 588 | { |
605 | | - for (auto&& it : *current_item.m_data.m_value.object) |
| 589 | + stack.reserve(object->size()); |
| 590 | + for (auto&& it : *object) |
606 | 591 | { |
607 | 592 | stack.push_back(std::move(it.second)); |
608 | 593 | } |
609 | | - |
610 | | - current_item.m_data.m_value.object->clear(); |
611 | 594 | } |
612 | 595 |
|
613 | | - // it's now safe that current_item get destructed |
614 | | - // since it doesn't have any children |
| 596 | + while (!stack.empty()) |
| 597 | + { |
| 598 | + // move the last item to local variable to be processed |
| 599 | + basic_json current_item(std::move(stack.back())); |
| 600 | + stack.pop_back(); |
| 601 | + |
| 602 | + // if current_item is array/object, move |
| 603 | + // its children to the stack to be processed later |
| 604 | + if (current_item.is_array()) |
| 605 | + { |
| 606 | + std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack)); |
| 607 | + |
| 608 | + current_item.m_data.m_value.array->clear(); |
| 609 | + } |
| 610 | + else if (current_item.is_object()) |
| 611 | + { |
| 612 | + for (auto&& it : *current_item.m_data.m_value.object) |
| 613 | + { |
| 614 | + stack.push_back(std::move(it.second)); |
| 615 | + } |
| 616 | + |
| 617 | + current_item.m_data.m_value.object->clear(); |
| 618 | + } |
| 619 | + |
| 620 | + // it's now safe that current_item get destructed |
| 621 | + // since it doesn't have any children |
| 622 | + } |
| 623 | +#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_HAS_EXCEPTIONS) |
615 | 624 | } |
| 625 | + catch (...) // NOLINT(bugprone-empty-catch) |
| 626 | + { |
| 627 | + // Recursion avoidance has issue allocating temporary space. This may have been `std::bad_alloc` |
| 628 | + // or any other exception thrown by a custom allocator. |
| 629 | + // RAII will correctly clean up anything moved into `stack`. |
| 630 | + // Then we continue with regular recursion based destroy, which will not heap allocate. |
| 631 | + } |
| 632 | +#endif |
616 | 633 | } |
617 | 634 |
|
618 | 635 | switch (t) |
|
0 commit comments