考虑一下std::map<const char *, MyClass*>.
如何访问MyClass地图指向的对象的成员(变量或函数)?
// assume MyClass has a string var 'fred' and a method 'ethel'
std::map<const char*, MyClass*> MyMap;
MyMap[ "A" ] = new MyClass;
MyMap.find( "A" )->fred = "I'm a Mertz"; // <--- fails on compile
MyMap.find( "A" )->second->fred = "I'm a Mertz"; // <--- also fails
Run Code Online (Sandbox Code Playgroud)
编辑 - 根据Xeo的建议
我发布了虚拟代码.这是真正的代码.
// VarInfo is meta-data describing various variables, type, case, etc.
std::map<std::string,VarInfo*> g_VarMap; // this is a global
int main( void )
{ …Run Code Online (Sandbox Code Playgroud) 我正在考虑一个棋盘设计,并想做一些事情:
typedef std::map <std::string, CheckerPiece> MapType;
MapType CheckerBoard;
CheckerBoard.insert({"a1", null});
Run Code Online (Sandbox Code Playgroud)
这是允许的,还是有办法做类似的事情?我的想法是,我想保持一个板状态,同时将CheckerPiece对象从一个位置移动到另一个位置.
编辑: 沿着相同的路线,是否可以执行以下操作:
CheckerBoard.insert({"a1", new CheckerPiece()});
Run Code Online (Sandbox Code Playgroud) 如果地图中只有单个元素,那么std :: map iterator会减少什么返回?这是示例代码
#include <map>
#include <stdio.h>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1, 1));
//std::map<int, int>::iterator it = m.begin();
std::map<int, int>::iterator it = m.upper_bound(0);
printf("isbegin: %d\n", it == m.begin());
--it;
bool isend = it == m.end();
printf("isend: %d\n", isend);
}
Run Code Online (Sandbox Code Playgroud)
在Windows上它将打印isend:1,在Linux上使用g ++ 4.6它将打印isend:0.
问题:上面的减量真的是UB的情况吗?如果没有,那么结果是正确的 - Windows还是Linux?
更新:修改代码以显示调用upper_bound
我在最后一天一直在解决这个问题,我仍然对以下代码的解决方案感到失望:
#include <stdio.h>
#include <iostream>
#include <map>
int main()
{
std::map<char *, char *> ourmap;
std::map<char *, char *>::iterator ourmap_it;
ourmap["hello"] = "world";
ourmap["hello"] = "earth";
char * key = new char[5];
key[0] = 'h';
key[1] = 'e';
key[2] = 'l';
key[3] = 'l';
key[4] = 'o';
char * key_other = new char[5];
key_other[0] = 'h';
key_other[1] = 'e';
key_other[2] = 'l';
key_other[3] = 'l';
key_other[4] = 'o';
ourmap[key] = "venus";
ourmap[key] = "mars";
ourmap[key_other] = "jupiter";
for (ourmap_it = …Run Code Online (Sandbox Code Playgroud) 我用这种方式定义了一个地图:
map<unsigned int, map<unsigned int, std::shared_ptr<MyObject>>> map;
Run Code Online (Sandbox Code Playgroud)
第一张地图预先初始化了一些键和空地图(内部地图).
我有一段用这张地图操作的代码:
for(auto mapElement : map){
//cout << "1) " << mapElement.second.size() << endl;
if(mapElement.second.size()>0){
// do something
}
mapElement.second.clear();
cout << "2) " << mapElement.second.size() << endl;
}
for(auto mapElement : overwrittenMsgs){
cout << "3) " << mapElement.second.size() << endl;
}
Run Code Online (Sandbox Code Playgroud)
这是一次迭代的可能输出:
1) 2
2) 0
1) 1
2) 0
3) 2
3) 1
Run Code Online (Sandbox Code Playgroud)
所以它似乎clear()并没有真正起作用.
我可以通过更换解决这个问题mapElement.second.clear();有map.at(mapElement.first).clear();.
这种行为的原因是什么?
我面临多线程应用程序中的奇怪崩溃:
static std::map<int, std::string> g_params;
Thread 1
(void)lock(map_mutex);
g_params[iParamID] = sValue;
(void)unlock(map_mutex);
Thread 2
(void)lock(map_mutex);
std::map<int, std::string>::iterator it;
for (it = g_params.begin(); it != g_params.end(); ++it)
{
// process it->first and it->second, w/o modifying them
}
g_params.clear(); // the crash occurs here: #5 0x76a3d08c in *__GI___libc_free (mem=0x703070c8) at malloc.c:3672
//#14 std::map<int, std::string, std::less<int>, std::allocator<std::pair<int const, std::string> > >::clear (this=0xb4b060)
(void)unlock(map_mutex);
Run Code Online (Sandbox Code Playgroud)
其中锁定和解锁是:
int lock(pthread_mutex_t mutex)
{
return pthread_mutex_lock(&mutex);
}
int unlock(pthread_mutex_t mutex)
{
return pthread_mutex_unlock(&mutex);
}
Run Code Online (Sandbox Code Playgroud)
崩溃发生非常罕见,很难预测重现它的场景.互斥体应该保证地图不会从一个线程改为另一个,对吧?
我们考虑一下这段代码:
std::map< int, char > charMap;
for( auto& i : charMap )
{
charMap[ i.first + 1 ] = charMap[ i.first ];
charMap.erase( i.first );
}
Run Code Online (Sandbox Code Playgroud)
假设地图有一些带有randomed键的值.我试图将键移动1.这不起作用,因为循环继续.有没有一种快速的方法使它工作?
为什么打印下面的代码1,即使我在地图中插入了两个元素?
#include <iostream>
#include <map>
#include <string>
#include <utility>
struct Foo
{
Foo(int bar, const std::string& baz)
: bar(bar)
, baz(baz)
{}
int bar;
std::string baz;
bool operator<(const Foo& rhs) const
{
if (bar < rhs.bar && baz < rhs.baz)
{
return true;
}
else
{
return false;
}
}
};
int main()
{
Foo first(0, "test");
Foo second(1, "test");
std::map<Foo, std::string> m;
m.insert(std::make_pair(first, "test"));
m.insert(std::make_pair(second, "test1"));
std::cout << m.size() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
第二个电话insert()说我们已经在地图中有该项目.为什么?
由于输入错误,我之前的问题 …
据我所知,我们绝不应该使用关系运算符来比较两个const字符串<>。因为它比较地址而不是值:
const char* sz1 = "Hello";
const char* sz2 = "hello";
if(sz1 < sz2);// not valid. So use strcmp instead.
Run Code Online (Sandbox Code Playgroud)
map, multimap, set, multiset对它们施加了限制,key因此应该对键进行一些比较以对容器中的元素进行排序。键的默认运算符是<operator。在创建之前,一切都是清楚的map, set,const char*然后得到错误的结果:
std::set<const char*> scp{ "Hello", "World", "C++", "Programming" };
std::set<std::string> sstr{ "Hello", "World", "C++", "Programming" };
// error
std::copy(scp.cbegin(), scp.cend(), std::ostream_iterator<const char*>(std::cout, " "));
std::cout << std::endl;
// Ok
std::copy(sstr.cbegin(), sstr.cend(), std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
Run Code Online (Sandbox Code Playgroud)
显然,只要类已定义为可以正常工作,就可以scp将指向指针的字符串比较sstr为OK …
假设您有一个不可默认构造的类。
class A {
private:
int a;
public:
A() = delete;
A(int a0) : a(a0) {}
};
Run Code Online (Sandbox Code Playgroud)
现在,我们有一些地图 Int --> A, std::map<int, A> mapping。假设我们要为某个键 0 创建一个新映射,如果键存在,我们要替换旧值。对默认可构造类执行此操作的方法是:
mapping[0] = A(4);
Run Code Online (Sandbox Code Playgroud)
然而,这对于类 A 将失败,因为 operator[] 首先构造 A 的默认实例,然后才分配 的值A(4)。通常这样做的一种方法(即对于不可默认构造的类)是这样的:
auto it = mapping.find(0);
if (it == mapping.end()) {
mapping.insert(0, A(4));
}
else {
it->second = A(4);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:这真的是(C++)预期的方法吗?我觉得这不可能是对的;作为一名程序员,我不想为这么少的代码编写这么多代码。但似乎没有简单的出路:我已经查找了常见的地图方法(插入、emplace、emplace_hint),如果键已经存在,它们都不会执行任何操作。