Search code examples
c++stringfunctionrefactoringstdstring

Cut-over interfaces from const char*, char* arguments to std::string


I am working on a legacy C++ code and needs aggressive refactoring. Main problem in the code is, passing const char*, char* arguments heavily as below. const char* variables are to pass internal char arrays (mostly user inputs) to validate and 'char*` to get any error details from the extended validators normally. This type of codes are everywhere in the codebase.

virtual bool ValidateField(const char* pointerToDataBuffer, char* error)
{
    // extended codes by client teams.
}

I am thinking of changing the interfaces as below,

virtual bool ValidateField(const std::string copyOfBufferInside, std::string& error)
{
   // do stuff as before.
}

My questions:

  1. Does this have huge performance issues? due to std::string construction. Normally internal buffers are about 0-31 in length, could increase in the future.
  2. Any other compact refactoring suggestions for this case, please suggest?

Note: Compiler is GCC 4.9.3.

EDITED: Internal buffer variables are in char[], not std::string. Might convert to std::string in the future. But that is not the case here.


Solution

  • Consider using type-based error-handling and boost::string_view to be able to handle all kinds of string-like inputs:

    http://coliru.stacked-crooked.com/a/22e9ec17b14992d1

    #include <string>
    #include <boost/variant.hpp>
    #include <boost/utility/string_view.hpp>
    #include <iostream>
    #include <type_traits>
    
    struct validation
    {
        struct error
        {
            std::string message;
        };
    
        struct success
        {
    
        };
    
        using result = boost::variant<success, error>;
    
        template<class OnSuccess, class OnFailure>
        struct visitor_impl : boost::static_visitor<void>
        {
            template<class A1, class A2>
            visitor_impl(A1&& s, A2&& f)
            : on_success(s)
            , on_failure(f)
            {}
    
            void operator()(success const&) const
            {
                on_success();
            }
    
            void operator()(error const& f) const
            {
                on_failure(f.message);
            }
    
            OnSuccess on_success;
            OnFailure on_failure;
        };
    
        template<class OnSuccess, class OnFailure>
        static auto visitor(OnSuccess&& s, OnFailure&& f)
        {
            using success_f = typename std::decay<OnSuccess>::type;
            using failure_f = typename std::decay<OnFailure>::type;
            return visitor_impl<success_f, failure_f>
            {
                std::forward<OnSuccess>(s),
                std::forward<OnFailure>(f)
            };
        }
    
    };
    
    validation::result ValidateField(boost::string_view value)
    {
        auto result = validation::result(validation::success {});
        if (value != "foo")
            result = validation::error { "not foo" };
        return result;
    }
    
    
    
    int main()
    {
        std::string bar = "bar";
        boost::apply_visitor(validation::visitor(
                            []() { std::cout << "is foo\n"; },
                            [](std::string const& msg) { std::cout << msg << '\n'; }
                        ), ValidateField(bar));
    
        std::string foo = "foo";
        boost::apply_visitor(validation::visitor(
                            []() { std::cout << "is foo\n"; },
                            [](std::string const& msg) { std::cout << msg << '\n'; }
                        ), ValidateField(foo));
    
        const char* pfoo = "foo";
        boost::apply_visitor(validation::visitor(
                            []() { std::cout << "is foo\n"; },
                            [](std::string const& msg) { std::cout << msg << '\n'; }
                        ), ValidateField(pfoo));
    
    
    }
    

    expected output:

    not foo
    is foo
    is foo