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

时间:2009-01-05 06:44:36

标签: c++ string

有没有办法取消定义chars和wchar_t的字符串和字符串的+ =?

基本上我想避免以下错误:

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 个答案:

答案 0 :(得分:9)

你无法停用某个类的特定函数(此处为std :: basic_string),因为它的界面明显(并且正式)允许该操作。试图使操作员超载只会搞砸。

现在,你可以使用私有继承或组合将“std :: basic_string”包装在另一个类中,然后使用公共接口作为std :: basic_string部分的代理,但只有你希望可以使用的功能。

我建议先用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;
}

我认为它会干净地解决你的问题,但你必须包装所有的功能。

答案 1 :(得分:8)

大多数源代码管理系统允许您在签入期间对代码运行完整性检查。因此,您可以设置测试以执行验证并拒绝签入失败:

示例:

测试脚本:

#!/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

此脚本伪造了上面两个运算符的添加(实际上没有更改源)。即使原始代码编译,这也会导致使用operator + with strings和char失败。

注意:操作员+ =从litb偷来的想法。谁已经删除了他的例子。但信用到期。

答案 2 :(得分:3)

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

2)在此类中重载operator+=(int val)并将其设为私有。

3)将此类用于所有字符串操作。

这会使编译器在执行以下操作时标记错误:

MyString str;
str += 27;

答案 3 :(得分:3)

没有简单的方法来阻止它,但有一种简单的方法可以找到它。编写一个使用此运算符的小程序,然后查看运算符的错位符号+ =您想要禁止。此符号是唯一的字符串。作为自动化测试的一部分,使用DUMPBIN(或等效的Linux / Mac工具)检查目标文件中是否存在这个受损的符号。