从operator []返回对映射char *的引用

时间:2016-06-07 12:56:08

标签: c++

我有一个数据结构:

#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*

3 个答案:

答案 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>