我有一个数据结构:
#include <map>
struct array{
map<const char*, char*> data;
//constructor
array(const char* key, char* value = ""){
data.insert(pair<const char*, char*>(key, value));
}
//overloaded operator[] seems to be my problem
char* operator[](const char* key) { return (char*)data[key]; }
};
现在,在没有重载作业operator=
的情况下,我试驾了
它是这样的:
array var("first", "second");
var["third"] = "fourth"; //and my compiler (gcc) is angry about this
现在,我的编译器返回了以下错误:
functions.cpp:13:18:错误:左值作为赋值的左操作数
问题:有什么不明白的吗?我怎么能够
从map::data["key"]
返回operator[]
的地址,
以便var["third"] = "fourth";
正常工作?请注意,我不想用c ++的字符串类型来做这件事。严格char*
。
答案 0 :(得分:3)
有什么我不理解的吗?
您将按值返回指针。这意味着调用者将收到指针的副本。调用者无法使用地图中指针的副本对地图中的指针进行更改。
如何从operator []返回map :: data [“key”]的地址,以便var [“third”] =“4th”;工作正常吗?
返回对它的引用:
char*& operator[](const char* key) { /* ... */ }
为了实现这一点,你需要摆脱多余的演员阵容:
return data[key];
你的程序中的另一个问题是你在地图中存储非常量char*
,但你用字符串文字初始化那些指针const
。这种转换在c ++ 11中是非法的,这意味着你的程序是不正确的。甚至在c ++ 11之前,由于标准c ++已经存在,这种转换已被弃用。
执行此操作的危险在于您可能会通过非const指针意外修改const字符串,这会导致未定义的行为。
解决方案:如果不需要修改字符串内容,请在地图中使用const char*
指针。如果需要修改 ,则指向从字符串文字中复制的单独分配的char
数组。执行后者的最简单方法是使用std::string
作为值类型,但如果您不想这样做,那么您可以自己管理数组。
您的计划中的第三个问题是,您似乎认为var["third"]
可以保证找到使用"third"
初始化的密钥。这个假设是错误的。单独 - 但相同 - 字符串文字不保证具有相同的地址。
解决方案:使用std::string
作为键,或使用自定义比较函数,根据内容比较字符串。提示:使用std::strcmp
来实现仿函数。
P.S。您似乎没有operator[](...)
的任何重载,因此它不是“重载”。
答案 1 :(得分:2)
有什么我不理解的吗?
是的,我认为您对代码及其意图感到困惑。严格来说,答案是您尝试在仅允许rvalue
的地方使用lvalues
,即在作业的lhs上使用char*& operator[](const char* key) { return data[key]; }
。要解决这个直接问题,您需要将运营商更改为:
var["third"][0] = 'a';
(即返回对地图中包含的指针的引用)。 这会编译,但我不认为这个结构会做你想要的。例如,修改地图条目的内容字符串,如下所示:
std::strings
如果您使用字符串文字来填充它,将是未定义的行为,就像您在示例中所做的那样。
最好接受评论者的建议并转而使用06-07 14:35:30.482 18292-18292/com.example.mmido.trivelgob2b E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.mmido.trivelgob2b, PID: 18292
java.lang.IllegalArgumentException: DrawerLayout must be measured with MeasureSpec.EXACTLY.
at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:1036)
at android.view.View.measure(View.java:16971)
at android.widget.ScrollView.measureChildWithMargins(ScrollView.java:1237)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:340)
at android.widget.ScrollView.onMeasure(ScrollView.java:326)
at android.view.View.measure(View.java:16971)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5374)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1621)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:742)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:607)
at android.view.View.measure(View.java:16971)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5374)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:340)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
at android.view.View.measure(View.java:16971)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5374)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1621)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:742)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:607)
at android.view.View.measure(View.java:16971)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5374)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:340)
at android.view.View.measure(View.java:16971)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5374)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1621)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:742)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:607)
at android.view.View.measure(View.java:16971)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5374)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:340)
at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2337)
at android.view.View.measure(View.java:16971)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2254)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1315)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1513)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1192)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6172)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:788)
at android.view.Choreographer.doCallbacks(Choreographer.java:591)
at android.view.Choreographer.doFrame(Choreographer.java:560)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:774)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5398)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:940)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
at dalvik.system.NativeStart.main(Native Method)
。
答案 2 :(得分:1)
要进行编译,您必须将operator []签名更改为:
char*& operator[](const char* key) { return data[key]; }
但是你会得到警告和可能的UB,因为字符串文字是const数组,而你想将它分配给非const char*
。要平息这些警告,您必须进行其他更改,所有char*
至const char*
:
struct array{
std::map<const char*, const char*> data;
//constructor
array(const char* key, const char* value = ""){
data.insert(std::pair<const char*, const char*>(key, value));
}
//overloaded operator[] seems to be my problem
const char*& operator[](const char* key) { return data[key]; }
};
但也许这不是你想要的。
最佳解决方案是将std::map<const char*, char*>
切换为std::map<std::string, std::string>