代码之家  ›  专栏  ›  技术社区  ›  rerun

寻找一些重构建议

  •  0
  • rerun  · 技术社区  · 16 年前

    我需要编写一些代码来替换一个被无数次使用的函数。函数的问题是返回指向静态分配缓冲区的指针,这是一个荒谬的问题。我终于能够证明间歇性高负载错误是由不良实践造成的。

    我正在替换的函数有一个签名 char * paddandtruncate(char *,int) char * paddandtruncate(float,int) char * paddandtruncat(int,int) . 每个函数都返回一个指向静态分配缓冲区的指针,该缓冲区在后续调用中被覆盖。

    我有三个常数,一个是

    1. 几乎没有时间解决这个问题。

    我想要一些关于风格和可能的重构想法的意见。

    该系统基于填充有空间的固定宽度字段,并且存在一些架构问题。由于该项目的规模约为1000000行,因此无法解决这些问题。

    起初,我计划允许数据在创建后更改,但认为不可变对象提供了更安全的解决方案。

        using namespace std;
    class SYSTEM_DECLSPEC CoreString
    {
    private:
         friend ostream & operator<<(ostream &os,CoreString &cs);
    
         stringstream   m_SS          ;
         float          m_FltData     ;
         long           m_lngData     ;
         long           m_Width       ;
         string         m_strData     ;
         string                  m_FormatedData;
         bool           m_Formated    ;
         stringstream    SS            ;
    
    
    public:
    
         CoreString(const string &InStr,long Width):
                 m_Formated(false),
                 m_Width(Width),
                 m_strData(InStr)
                 {
                         long OldFlags = SS.flags();
                         SS.fill(' ');
                         SS.width(Width);
                         SS.flags(ios::left);
                         SS<<InStr;
                         m_FormatedData = SS.str();
                 }
    
         CoreString(long longData , long Width):
                 m_Formated(false),
                 m_Width(Width),
                 m_lngData(longData)
                 {
                         long OldFlags = SS.flags();
                         SS.fill('0');
                         SS.precision(0);
                         SS.width(Width);
                         SS.flags(ios::right);
                         SS<<longData;
                         m_FormatedData = SS.str();
                 }
    
         CoreString(float FltData, long width,long lPerprecision):
                 m_Formated(false),
                 m_Width(width),
                 m_FltData(FltData)
                 {
                         long OldFlags = SS.flags();
                         SS.fill('0');
                         SS.precision(lPerprecision);
                         SS.width(width);
                         SS.flags(ios::right);
                         SS<<FltData;
                         m_FormatedData = SS.str();
                 }
    
         CoreString(const string &InStr):
                 m_Formated(false),
                 m_strData(InStr)
                 {
                         long OldFlags = SS.flags();
                         SS.fill(' ');
                         SS.width(32);
                         SS.flags(ios::left);
                         SS<<InStr;
                         m_FormatedData = SS.str();
                 }
     public:
         operator const char   *() {return m_FormatedData.c_str();}
         operator const string& () const {return m_FormatedData;}
         const string& str() const ; 
    
    };
    
    const string& CoreString::str() const
    {
         return m_FormatedData;
    }
    
    ostream & operator<<(ostream &os,CoreString &cs)
    {
         os<< cs.m_Formated;
         return os;
     }
    
    5 回复  |  直到 16 年前
        1
  •  2
  •   Mark Ransom    16 年前

    如果你的意思是“对来电者没有影响”,那么你的选择是非常有限的。您不能返回需要调用方释放的任何内容。

    冒着用一个坏的解决方案替换另一个坏的解决方案的风险,最快和最简单的解决方案可能是这样的:不要使用单一的静态缓冲区,而是使用它们的池,并在每次调用函数时循环使用它们。确保选择缓冲区的代码是线程安全的。

        2
  •  2
  •   Tim Sylvester    16 年前

    听起来系统是线程化的,对吗?如果只是因为在您仍然使用之前的输出时再次调用其中一个函数不安全,那么每次都应该以相同的方式进行。

    大多数编译器都有一种将变量标记为“线程本地数据”的方法,以便根据访问它的线程的不同,该变量具有不同的地址。在gcc中,它是 __thread __declspec(thread)

    如果您需要能够在不覆盖结果的情况下从同一线程多次调用这些函数,我看不到任何完整的解决方案,只能强制调用方释放结果。您可以使用一种混合方法,其中每个线程都有固定数量的缓冲区,这样调用者可以在不覆盖先前结果的情况下进行多达N次调用,而不管其他线程在做什么。

        3
  •  1
  •   Mark Ransom    16 年前

    您发布的代码有一个巨大的问题-如果调用方将返回值分配给const char*,编译器将进行静默转换并销毁临时CoreString对象。现在您的指针将无效。

        4
  •  1
  •   David Thornley    16 年前

    我不知道呼叫者将如何使用它,但是使用 new 变成 auto_ptr<> 这可能有用。它可能满足标准1(如果没有看到正在使用的代码,我无法判断),并且可能是一个非常快速的修复。最大的问题是它使用了很多动态内存,这会减慢速度。使用placement new之类的工具,您可以做一些事情,但这可能不会很快编码。

    如果不能使用动态存储,那么就只能使用非动态存储,如果不使用缓冲区循环池或线程本地缓冲区之类的东西,就真的没什么可做的了。

        5
  •  0
  •   Steve Jessop    16 年前

    “间歇性高负载错误”是由争用条件引起的,其中一个线程在另一个线程使用完静态缓冲区之前踩坏了静态缓冲区,对吗?

    所以,切换到使用每个线程的输出缓冲区,使用平台提供的任何线程本地存储机制(我想是Windows)。

    没有同步争用,线程之间没有干扰,并且根据您所说的当前实现旋转缓冲区,几乎可以肯定调用代码根本不需要更改。如果当前实现使用多个缓冲区,它不能依赖于每次使用的相同缓冲区。

    我可能不会从头开始这样设计API,但它实现了您当前的API,而不会对其进行重大更改,也不会影响性能。