只是在优化一些std::map
代码。地图包含通过字符串标识符访问的对象。
示例:
std::map<std::string, CVeryImportantObject> theMap;
...
theMap["second"] = new CVeryImportantObject();
现在,当将find-function用作theMap->find("second")
时,String将转换为std::string("second")
,这会导致新的字符串分配(在使用IDL = 2时使用Visual Studio)。
1。是否有可能使用仅字符串类来避免此类分配?
我故意尝试使用另一个String-Class:
std::map<CString, CVeryImportantObject> theMap;
此代码也有效。但是CString 确实是一个对象。
而且:如果从地图中删除一个对象,我需要释放相关对象和密钥,是吗?
有什么建议吗?
答案 0 :(得分:5)
现在,当使用find-function作为Map-&gt; find(“second”)时, 字符串转换为std :: string(“second”),这会导致new 字符串分配(使用IDL = 2时使用Visual Studio)。
这是一个标准问题,在C ++ 14中修复了有序容器。最新版本的VS,VS 14 CTP(预发布)包含a fix for this issue,其他实现的新版本也是如此。
如果你需要避免分配,你可以尝试像llvm::StringRef
这样的类,可以互换地引用std::string
或字符串文字,但是你将会尝试在外部处理所有权。
您可以尝试unique_ptr<char[], maybe_delete>
之类的内容,有时会删除内容。尽管如此,这有点混乱。
并且:如果你从地图中删除一个对象,我需要释放它们 我有相关的对象和关键吗?
地图会自动为您破坏密钥和值。对于一个释放它自己的资源的类,如std::string
,这是编写C ++的唯一理智方式,那么你可以擦除而不必担心资源清理。
答案 1 :(得分:0)
如果始终使用字符串常量作为键,则在使用适当的比较器时,可以在映射中使用const char *
作为键类型:
struct PCharCompare {
bool operator()( const char *s1, const char *s2 ) const { return strcmp( s1, s2 ) < 0; }
};
std::map< const char *, CVeryImportantObject, PCharCompare> theMap;
注意:你必须要小心并且需要了解它是如何工作的,因为它很容易导致UB:
void foo() {
char buffer[256];
snprintf( buffer, sizeof( buffer ), "blah" );
theMap.insert( std::make_pair( buffer, Object ) );
} // ups dangled pointer in the map
至于优化,std::string
创建不太可能是罪魁祸首。您可以尝试使用std::unordered_map
或类似的内容进行优化
答案 2 :(得分:-1)
现在,当使用find-function作为Map-&gt; find(“second”)时, 字符串转换为std :: string(“second”),这会导致new 字符串分配
不一定。 VC使用小字符串优化(SSO)。这意味着对于短于"second"
的字符串,根本不应该在堆上进行分配;而是将字符直接存储在临时创建的std::string
对象中。
这仍然不是免费的(因为必须创建std::string
,虽然内部没有任何动态分配),但应该足够好。这真的是你的顾虑吗?机会非常高,不会导致任何可衡量的性能下降。
- 是否有可能使用仅字符串类来避免此类分配?
醇>
不是真的,除了其他答案中提到的C ++ 14修复。使用char const *
作为密钥类型非常危险,因为std::map
只会存储实际地址,而不会存储密钥副本。
如果我是你,如果我真的遇到性能问题,我不会直接使用std::map
但是创建我自己的容器类来包装std::map<char const *, T, CustomComparison>
并在内部执行硬指针。 / p>
template <class ValueType>
class FastStringMap
{
private:
struct Comparison
{
bool operator()(char const *lhs, char const *rhs) const
{
return strcmp(lhs, rhs) > 0;
}
};
typedef std::map<char const *, ValueType, Comparison> WrappedMap;
WrappedMap m_map;
public:
typedef typename WrappedMap::iterator iterator;
typedef typename WrappedMap::const_iterator const_iterator;
bool insert(char const *key, ValueType const &value)
{
if (m_map.find(key) != m_map.end())
{
return false;
}
else
{
char *copy = new char[strlen(key) + 1];
strcpy(copy, key);
try
{
return m_map.insert(std::make_pair(copy, value)).second;
}
catch (...)
{
delete copy;
throw;
}
}
}
~FastStringMap()
{
for (iterator iter = m_map.begin(); iter != m_map.end(); ++iter)
{
delete[] iter->first;
}
}
iterator find(char const *key)
{
return m_map.find(key);
}
const_iterator find(char const *key) const
{
return m_map.find(key);
}
// further operations
};
要像这样使用:
FastStringMap<int> m;
m.insert("AAA", 1);
m.insert("BBB", 2);
m.insert("CCC", 3);
std::cout << m.find("AAA")->second;
请注意,您可以通过对字符类型(对于std::wstring
支持)进行模板化或通过提供“真正的”迭代器类(使用Boost Iterator Facade)来使其更加复杂。
并且:如果你从地图中删除一个对象,我需要释放它们 我有相关的对象和关键吗?
如果您使用std::string
,请执行。如果你使用char const *
并且如果指针指向动态分配的内存(如我的例子中所示),那么是。