| 525 | == Pointers == |
| 526 | |
| 527 | === Normal Pointers === |
| 528 | |
| 529 | A pointer should always be checked before using. You should never assume that the pointer will be valid. |
| 530 | This is a good coding style and should be done. |
| 531 | {{{ |
| 532 | #!cpp |
| 533 | if (pData != NULL) |
| 534 | { |
| 535 | int nSize = pData->GetSize(); |
| 536 | ... |
| 537 | } |
| 538 | }}} |
| 539 | |
| 540 | This is a bad coding style and should not be done. |
| 541 | {{{ |
| 542 | #!cpp |
| 543 | int nSize = pData->GetSize(); |
| 544 | }}} |
| 545 | |
| 546 | When you are no longer using a pointer you should set it to NULL so that it is clear that it is no longer valid. |
| 547 | {{{ |
| 548 | #!cpp |
| 549 | ... |
| 550 | delete pData; |
| 551 | pData = NULL; |
| 552 | }}} |
| 553 | |
| 554 | === Smart Pointers === |
| 555 | |
| 556 | ==== Our Code ==== |
| 557 | |
| 558 | The !MapGuide Ptr template class acts as a smart pointer and should be used whenever possible. |
| 559 | Example: |
| 560 | {{{ |
| 561 | #!cpp |
| 562 | MgRepository* MgServerResourceService::CreateRepository(CREFSTRING repositoryType, CREFSTRING repositoryName) |
| 563 | { |
| 564 | Ptr<MgRepository> repository = 0; |
| 565 | |
| 566 | MG_RESOURCE_SERVICE_TRY() |
| 567 | |
| 568 | MgResourceServiceUtil::CheckArgument(!repositoryName.empty()); |
| 569 | |
| 570 | if (MgRepositoryType::Library == repositoryType) |
| 571 | { |
| 572 | repository = new MgLibraryRepository(repositoryName, this); |
| 573 | } |
| 574 | else if (MgRepositoryType::Session == repositoryType) |
| 575 | { |
| 576 | repository = new MgSessionRepository(repositoryName, this); |
| 577 | } |
| 578 | else |
| 579 | { |
| 580 | throw new MgInvalidRepositoryTypeException(__FILE__, __LINE__); |
| 581 | } |
| 582 | |
| 583 | MgResourceServiceUtil::CheckMemory(repository); |
| 584 | |
| 585 | MG_RESOURCE_SERVICE_CATCH_AND_THROW() |
| 586 | |
| 587 | assert(0 == mgException); |
| 588 | |
| 589 | (*repository).AddRef(); // Ownership is transferred to the caller |
| 590 | |
| 591 | return repository; |
| 592 | } |
| 593 | }}} |
| 594 | |
| 595 | ==== 3rd Party Library ==== |
| 596 | |
| 597 | Wherever possible the standard C++ smart pointer should be used when dealing with 3rd party libraries. |
| 598 | |
| 599 | The following is some sample code that uses the standard C++ smart pointer along with a typical !MapGuide Exception handling mechanism: |
| 600 | |
| 601 | {{{ |
| 602 | #!cpp |
| 603 | Bar* Foo::CreateBar() |
| 604 | { |
| 605 | auto_ptr<Bar> bar; |
| 606 | |
| 607 | MG_TRY() |
| 608 | |
| 609 | bar = auto_ptr<Bar>(new Bar); |
| 610 | assert(0 != bar.get()); |
| 611 | bar.DoSomething(); // might throw an exception |
| 612 | |
| 613 | MG_CATCH_AND_THROW() |
| 614 | |
| 615 | return bar.release(); // release ownership of the smart pointer |
| 616 | } |
| 617 | }}} |
| 618 | |
| 619 | Standard C++ smart pointer notes: |
| 620 | 1. Never use auto_ptr objects as elements of STL containers because auto_ptr does not quite meet the requirements of a type you can put into containers (i.e. copies of auto_ptrs are not equivalent). |
| 621 | 1. Never use an array as an auto_ptr argument because auto_ptr's destructor invokes only non-array delete. |
| 622 | |
| 623 | The following code is a cleaned up version of the above sample code using some helper macros. |
| 624 | {{{ |
| 625 | #!cpp |
| 626 | Bar* Foo::CreateBar() |
| 627 | { |
| 628 | char* bar = 0; |
| 629 | |
| 630 | MG_TRY() |
| 631 | |
| 632 | bar = new char[256]; |
| 633 | assert(0 != bar); |
| 634 | DoSomething(bar); |
| 635 | |
| 636 | MG_CATCH() |
| 637 | |
| 638 | if (0 != mgException) |
| 639 | { |
| 640 | delete[] bar; |
| 641 | throw mgException; |
| 642 | } |
| 643 | |
| 644 | return bar; |
| 645 | } |
| 646 | }}} |
| 647 | |
| 648 | Note that MG_TRY(), MG_CATCH(), MG_THROW, MG_CATCH_AND_THROW and MG_CATCH_AND_RELEASE() macros can be anything specific to a !MapGuide component. |
| 649 | |
| 650 | Example macro definitions for the resource service: |
| 651 | {{{ |
| 652 | #!cpp |
| 653 | #define MG_RESOURCE_SERVICE_TRY() \ |
| 654 | MG_TRY() \ |
| 655 | |
| 656 | #define MG_RESOURCE_SERVICE_CATCH(methodName) \ |
| 657 | } \ |
| 658 | catch (XmlException& e) \ |
| 659 | { \ |
| 660 | MgStringCollection arguments; \ |
| 661 | STRING message; \ |
| 662 | \ |
| 663 | if (DB_LOCK_DEADLOCK == e.getDbErrno()) \ |
| 664 | { \ |
| 665 | message = MgUtil::GetResourceMessage( \ |
| 666 | MgResources::ResourceService, L"MgRepositoryBusy"); \ |
| 667 | } \ |
| 668 | else \ |
| 669 | { \ |
| 670 | MgUtil::MultiByteToWideChar(string(e.what()), message); \ |
| 671 | } \ |
| 672 | \ |
| 673 | arguments.Add(message); \ |
| 674 | mgException = new MgDbXmlException(methodName, __LINE__, __WFILE__, NULL, L"MgFormatInnerExceptionMessage", &arguments); \ |
| 675 | (static_cast<MgThirdPartyException*>(mgException.p))->SetErrorCode(e.getDbErrno()); \ |
| 676 | } \ |
| 677 | catch (DbException& e) \ |
| 678 | { \ |
| 679 | MgStringCollection arguments; \ |
| 680 | STRING message; \ |
| 681 | \ |
| 682 | if (DB_LOCK_DEADLOCK == e.get_errno()) \ |
| 683 | { \ |
| 684 | message = MgUtil::GetResourceMessage( \ |
| 685 | MgResources::ResourceService, L"MgRepositoryBusy"); \ |
| 686 | } \ |
| 687 | else \ |
| 688 | { \ |
| 689 | MgUtil::MultiByteToWideChar(string(e.what()), message); \ |
| 690 | } \ |
| 691 | \ |
| 692 | arguments.Add(message); \ |
| 693 | mgException = new MgDbException(methodName, __LINE__, __WFILE__, NULL, L"MgFormatInnerExceptionMessage", &arguments); \ |
| 694 | (static_cast<MgThirdPartyException*>(mgException.p))->SetErrorCode(e.get_errno()); \ |
| 695 | } \ |
| 696 | catch (DWFException& e) \ |
| 697 | { \ |
| 698 | MgStringCollection arguments; \ |
| 699 | arguments.Add(STRING(e.message())); \ |
| 700 | mgException = new MgDwfException(methodName, __LINE__, __WFILE__, NULL, L"MgFormatInnerExceptionMessage", &arguments); \ |
| 701 | } \ |
| 702 | catch (const XMLException& e) \ |
| 703 | { \ |
| 704 | MgStringCollection arguments; \ |
| 705 | arguments.Add(X2W(e.getMessage())); \ |
| 706 | mgException = new MgXmlParserException(methodName, __LINE__, __WFILE__, NULL, L"MgFormatInnerExceptionMessage", &arguments); \ |
| 707 | } \ |
| 708 | catch (const DOMException& e) \ |
| 709 | { \ |
| 710 | MgStringCollection arguments; \ |
| 711 | arguments.Add(X2W(e.msg)); \ |
| 712 | mgException = new MgXmlParserException(methodName, __LINE__, __WFILE__, NULL, L"MgFormatInnerExceptionMessage", &arguments); \ |
| 713 | \ |
| 714 | MG_CATCH(methodName) \ |
| 715 | |
| 716 | #define MG_RESOURCE_SERVICE_THROW() \ |
| 717 | MG_THROW() \ |
| 718 | |
| 719 | #define MG_RESOURCE_SERVICE_CATCH_AND_THROW(methodName) \ |
| 720 | MG_RESOURCE_SERVICE_CATCH(methodName) \ |
| 721 | \ |
| 722 | MG_RESOURCE_SERVICE_THROW() \ |
| 723 | }}} |
| 724 | |
| 725 | == Enumerations == |
| 726 | |
| 727 | Please use the following format when declaring enumerations. |
| 728 | |
| 729 | Example 1: |
| 730 | {{{ |
| 731 | #!cpp |
| 732 | enum MgDimensionality |
| 733 | { |
| 734 | mdXY = 0, /// XY |
| 735 | mdXYM, /// XY + Measure |
| 736 | mdXYZ, /// XYZ |
| 737 | mdXYZM, /// XYZ + Measure |
| 738 | }; |
| 739 | }}} |
| 740 | |
| 741 | Example 2: |
| 742 | {{{ |
| 743 | #!cpp |
| 744 | enum MgConnectionState |
| 745 | { |
| 746 | mcsOpen = 0, /// Connection is still open |
| 747 | mcsClose, /// Connection has been closed |
| 748 | mcsBusy /// Connection is busy processing other request |
| 749 | }; |
| 750 | }}} |
| 751 | |
| 752 | You will notice that the 1st letter of each word is part of the enumeration value. |
| 753 | Also, when using enumerations in your code ALWAYS do the following: |
| 754 | {{{ |
| 755 | #!cpp |
| 756 | ConnectionState::mcsOpen |
| 757 | }}} |
| 758 | Do NOT do the following: |
| 759 | {{{ |
| 760 | #!cpp |
| 761 | mcsOpen |
| 762 | }}} |
| 763 | |
| 764 | == Parentheses == |
| 765 | |
| 766 | Even if the operator precedence seems clear to you, it is best to use parentheses to avoid any confusion by others. |
| 767 | {{{ |
| 768 | #!cpp |
| 769 | if (a == b && c == d) // Bad |
| 770 | if ((a == b) && (c == d)) // Good |
| 771 | }}} |
| 772 | |
| 773 | == Assert == |
| 774 | |
| 775 | === .NET === |
| 776 | |
| 777 | Use Debug.Assert ( condition ) to do assertions. Do not use Trace.Assert as that will not be removed for release build. |
| 778 | |
| 779 | For C++ .NET projects you must do the following or else the Debug calls will still be called in release builds. |
| 780 | {{{ |
| 781 | #!cpp |
| 782 | #ifdef _DEBUG |
| 783 | Debug::WriteLine(SrsErrorMessage(status)); |
| 784 | #endif |
| 785 | }}} |
| 786 | |
| 787 | |
| 788 | |
| 789 | |