我正在寻找一种有效的方法来检查POD变量是否在两个周期之间被改变。我已经提出了这个解决方案:
class Foo {
public:
template<typename T>
bool isChanged(T& entry);
void endCycle();
private:
std::map<void*,size_t> entryMap; // <Address orig.,Size>
std::map<void*,void*>oldVals; // <Address orig., Address cpy.>
};
template<typename T> bool Foo::isChanged(T& entry)
{
entryMap[&entry] = sizeof(T);
if(oldVals[&entry] == NULL)
return false;
if(memcmp(&entry, oldVals[&entry], entryMap[&entry]))
return true;
else
return false;
}
void Foo::endCycle()
{
// Copy all the bytes to save them for the next cycle
for( std::map<void*,size_t>::iterator entryIt = entryMap.begin();
entryIt != entryMap.end();
++entryIt)
{
if(oldVals[entryIt->first] == NULL)
oldVals[entryIt->first] = malloc(entryIt->second);
memcpy(oldVals[entryIt->first], entryIt->first, entryIt->second);
}
}
现在我可以像这样使用它:
Foo gBar;
void aFunction()
{
int ar;
char ba[3][3];
// Some code where ar and ba are filled
if(gBar.isChanged(ar))
// Do Something
if(gBar.isChanged(ba))
// Do Something
gBar.endCycle();
}
这是一种有效的方法吗?我的目标是一种在各种循环调用函数中非常容易使用的方法。我从代码中清除了所有init和free逻辑。有什么建议?我特别不喜欢oldshool malloc,memcpy和memcmp,但我不知道如何做到这一点。
编辑:根据红色警报建议找到一个好的解决方案。
答案 0 :(得分:1)
我认为你可以在这里更有效地使用模板。
template <typename T>
class Foo
{
public:
static std::map<T*, T> values;
static bool isChanged(T& entry)
{
auto it = values.find(&entry);
if(it == values.end())
{
values[&entry] = entry;
}
else if(entry != it->second)
{
it->second = entry;
return true;
}
return false;
}
};
template <typename T>
std::map<T*, T> Foo<T>::values;
int main() {
int ar = 3;
cout << Foo<int>::isChanged(ar) << endl; // 0
ar = 4;
cout << Foo<int>::isChanged(ar) << endl; // 1
for(auto& value : Foo<int>::values)
cout << value.second << endl; // 4
return 0;
}
通过这种方式,您可以获得每种类型一个map
,并且您不必担心会无意中弄乱别名。您需要定义operator !=
并为您的类型设置一个工作副本构造函数,但这比盲目使用memcmp
和memcpy
要好得多。
如果你需要比较那些数组,你还可以为数组做进一步的模板特化(将会有更多的代码,但没有什么非常复杂的)
编辑:为了让您入门,这就是您的模板签名应如下所示:
template<class T, size_t N> bool isChanged(T(&entry)[N]); //will be called for stack allocated arrays
或者您可以使用char *来为所有值设置别名。这将允许您为所有内容使用单个地图(就像之前一样,但这没有memcpy
/ memcmp
)。它只适用于POD。我们可以在覆盖缓冲区时手动调用析构函数,但由于在类的析构函数中没有好的方法可以做到这一点,所以最好不要完全忽略堆分配的数据。
class Foo
{
std::map<char**, char*> values;
public:
~Foo()
{
for(auto& value : values)
{
delete[] value.second;
}
}
template<typename T> bool isChanged(T& entry)
{
char** addr = reinterpret_cast<char**>(&entry);
auto it = values.find(addr);
if(it == values.end())
{
alignas(T) char* oldBuf = new char[sizeof(T)];
T* oldEntry = new(oldBuf) T;
*oldEntry = entry;
values[addr] = oldBuf;
}
else if(entry != *(reinterpret_cast<T*>(it->second)))
{
T* oldEntry = new(it->second) T;
*oldEntry = entry;
return true;
}
return false;
}
};
答案 1 :(得分:0)
经过几个小时,我觉得我找到了一个很好的解决方案。通话保持简单,没有演员阵容。它比使用memcopy的C风格版本复杂得多,但我认为它更好,并且还有一个好处,它适用于复杂的数据而不仅仅是POD。
class Manager
{
public:
~Manager()
{
funcPtrs.clear();
}
void adFnc(void(*function)())
{
funcPtrs.push_back(function);
}
void runAll()
{
for(auto& val : funcPtrs)
val();
}
private:
std::vector<void (*)()> funcPtrs;
};
Manager gAllClearManager;
template<typename T>
class Data
{
public:
Data()
{
gAllClearManager.adFnc(clearValues);
}
static void clearValues()
{
values.clear();
}
static std::map<T*,std::vector<T>>& getValues() { return values; }
private:
static std::map<T*,std::vector<T>> values;
};
template <typename T>
static bool isChanged(T& entry)
{
const static Data<T>* dataP = new Data<T>();
static std::map<T*,std::vector<T>>& values = dataP->getValues();
auto it = values.find(&entry);
if(it == values.end())
{
values[&entry].push_back(entry);
}
else if(entry != it->second[0])
{
it->second[0] = entry;
return true;
}
return false;
}
template<typename T, size_t N>
bool isChanged(T (&entry)[N])
{
const static Data<T>* dataP = new Data<T>();
static std::map<T*,std::vector<T>>& values = dataP->getValues();
auto it = values.find(entry);
if( it == values.end())
{
for(int i = 0; i < N ; ++i )
values[entry].push_back(entry[i]);
return false;
}
else
{
for(int i = 0; i < N ; ++i )
{
if(it->second[i] != entry[i])
{
for(int j = 0; j < N ; ++j )
{
it->second[j] = entry[j];
}
return true;
}
}
}
return false;
}
template<typename T>
std::map<T*, std::vector<T>> Data<T>::values;
现在我可以像以下一样使用它:
int main() {
int ar;
std::string ba[6];
if(isChange(ar))
// Do something
if(isChange(ba))
// Do something
}
我的第一个模板终于工作了! :)再次感谢红色警报。