代码之家  ›  专栏  ›  技术社区  ›  Brian R. Bondy

如何避免大型代码库中的常见错误?

  •  6
  • Brian R. Bondy  · 技术社区  · 16 年前

    基本上,我希望避免如下错误:

    int age = 27;
    
    std::wstring str = std::wstring(L"User's age is: ");
    str += age;
    
    std::string str2 = std::string("User's age is: ");
    str2 += age;
    

    上述代码将向字符串中添加ascii字符27,而不是数字27。

    很明显,我知道如何修复这个问题,但我的问题是:在这种情况下,如何生成编译器错误?

    注意:您可以在std::string和int上重写+=以正确格式化字符串,但这不是我想要做的。我想在这些操作数上完全不允许使用此运算符。

    4 回复  |  直到 16 年前
        1
  •  9
  •   Klaim    16 年前

    不能停用特定功能 一个类(这里是std::basic_字符串),因为它的接口明确(正式)允许这种操作。试图让操作员超负荷工作只会把事情搞砸。

    我建议首先用typedef替换字符串类型:

    namespace myapp
    {
        typedef std::string String;
        typedef std::wstring UTFString;
    }
    

    然后,一旦应用程序在用myapp::string和myapp::UTFString(这些都是示例名称)替换std::string和std::wstring后编译良好,您就可以在某处定义包装类:

    namespace myapp
    {
    /** std::basic_string with limited and controlled interface.
        */
        template< class _Elem, class _Traits, class _Ax >
        class limited_string 
        {
        public:
            typedef std::basic_string< _Elem , _Traits, _Ax > _String; // this is for easier writing
            typedef limited_string< _Elem, _Traits, _Ax > _MyType; // this is for easier writing
    
        private:
            _String m_string; // here the real std::basic_string object that will do all the real work!
    
        public:
    
            // constructor proxies... (note that those ones are not complete, it should be exactly the same as the original std::basic_string
            // see some STL docs to get the real interface to rewrite)
            limited_string() : m_string {}
            limited_string( const _MyType& l_string ) : m_string( l_string.m_string ) {}
            limited_string( const _Elem* raw_string ) : m_string( raw_string ) {}
            //... etc...
    
            // operator proxies...
            _MyType& operator= ( const _MyType& l_string ) 
            {
                m_string = l_string.m_string;
            }
            // etc...
            // but we don't want the operator += with int values so we DON'T WRITE IT!
    
            // other function proxies...
            size_t size() const { return m_string.size(); } // simply forward the call to the real string!
            // etc...you know what i mean...
    
            // to work automatically with other STL algorithm and functions we add automatic conversion functions:
            operator const _Elem*() const { return m_string.c_str(); } 
    
            // etc..        
    
    
        };
    }
    

    // instead of those lines...
        //typedef std::string String; 
        //typedef std::wstring UTFString;
    
        // use those ones
        typedef limited_string< char, std::char_traits<char>, std::allocator<char> >                String; // like std::string typedef
        typedef limited_string< wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >       UTFString; // like std::wstring typedef 
    

    error C2676: binary '+=' : 'myapp::UTFString' does not define this operator or a conversion to a type acceptable to the predefined operator
    error C2676: binary '+=' : 'myapp::String' does not define this operator or a conversion to a type acceptable to the predefined operator
    

    以下是我编写的完整测试应用程序代码,以证明(在vc9上编译):

    #include <string>
    #include <iostream>
    
    namespace myapp
    {
    
        /** std::basic_string with limited and controlled interface.
        */
        template< class _Elem, class _Traits, class _Ax >
        class limited_string 
        {
        public:
            typedef std::basic_string< _Elem , _Traits, _Ax > _String; // this is for easier writing
            typedef limited_string< _Elem, _Traits, _Ax > _MyType; // this is for easier writing
    
        private:
            _String m_string; // here the real std::basic_string object that will do all the real work!
    
        public:
    
            // constructor proxies... (note that those ones are not complete, it should be exactly the same as the original std::basic_string
            // see some STL docs to get the real interface to rewrite)
            limited_string() : m_string {}
            limited_string( const _MyType& l_string ) : m_string( l_string.m_string ) {}
            limited_string( const _Elem* raw_string ) : m_string( raw_string ) {}
            //... etc...
    
            // operator proxies...
            _MyType& operator= ( const _MyType& l_string ) 
            {
                m_string = l_string.m_string;
            }
            // etc...
            // but we don't want the operator += with int values so we DON'T WRITE IT!
    
            // other function proxies...
            size_t size() const { return m_string.size(); } // simply forward the call to the real string!
            // etc...you know what i mean...
    
            // to work automatically with other STL algorithm and functions we add automatic conversion functions:
            operator const _Elem*() const { return m_string.c_str(); } 
    
            // etc..        
    
    
        };
    
        // instead of those lines...
        //typedef std::string String; 
        //typedef std::wstring UTFString;
    
        // use those ones
        typedef limited_string< char, std::char_traits<char>, std::allocator<char> >                String; // like std::string typedef
        typedef limited_string< wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >       UTFString; // like std::wstring typedef 
    }
    
    int main()
    {
        using namespace myapp;
    
        int age = 27;
    
        UTFString str = UTFString(L"User's age is: ");
        str += age; // compilation error!
        std::wcout << str << std::endl;
    
        String str2 = String("User's age is: ");
        str2 += age; // compilation error!
        std::cout << str2 << std::endl;
    
        std::cin.ignore();
    
        return 0;
    }
    

    我认为它会彻底解决您的问题,但您必须包装所有函数。

        2
  •  8
  •   Loki Astari    16 年前

    例子:

    测试脚本:

    #!/bin/tcsh
    # Pass the file to test as the first argument.
    
    echo "#include <string>\
    void operator+=(std::string const& , int const&);\
    void operator+=(std::string const& , int);"\
    | cat - $1 \
    | g++ -c -x c++ -  >& /dev/null
    
    
    echo $status
    

    这个脚本伪造了上面两个操作符的加法(实际上没有改变源代码)。这将导致运算符+与字符串和字符的任何使用失败,即使原始代码已编译。

    注意:操作员+=从litb窃取的想法。他后来删除了他的例子。但这是应得的。

        3
  •  3
  •   MSalters    16 年前

        4
  •  2
  •   G S    16 年前

    1) 创建自己的字符串类,该类继承/包含 std::string .

    operator+=(int val) 而且要保密。

    当您执行以下操作时,这将导致编译器标志错误:

    MyString str;
    str += 27;