传递参数到函数时,使用传值还是常量引用?

4

我应该将std::string作为参数按值传递还是按引用传递给一个函数。这个函数会将这些值存储在类的成员变量中。

当需要传递参数时,我总是感到困惑,不知道是按值传递还是按引用传递。请帮我解决这个疑惑。

以下是代码:

class DataStore {
public:
    void addFile(const string& filename, const set< std::string>& filePaths)
    {  
        if (dataStoreMap.insert(make_pair(filename, filePaths)).second)
        {
            cout << "Data Added" <<endl;
        }
        else
        {
            cout << "Data not Added" << endl;
        }
    }
private:
    // member variable
    map < string, set < string >  > dataStoreMap;
};

我应该像这样声明函数吗:
void addFile(const string& filename, const set< std::string>& filePaths)

或者
void addFile(const string filename, const set< std::string> filePaths)

两者都给出了相同的结果。如果存在内存分配或性能方面的问题。
上述函数调用来自cpp类。
DataStore ds;
set<string> setFileDirectory{ "1", "2", "3", "4", "6", "5" };
ds.addFile("file.txt", setFileDirectory);

setFileDirectory.erase(setFileDirectory.begin(), setFileDirectory.end());
setFileDirectory.insert({ "1", "2", "3", "4", "5", "6" });
ds.addFile("demo.txt", setFileDirectory);

任何详细的解释都将不胜感激。
谢谢。

非常感谢您的回复。我理解您的意思,但是当我需要使用值或引用时,仍然让我感到困惑。在这里,我将要在映射中存储值,所以传递值是好的选择?还是传递引用? - sam_k
你的问题是传值和传引用之间的区别吗? - IllusiveBrian
@Namfuak: 什么情况下该使用传递引用或传递值,让人感到困惑。 - sam_k
4个回答

3

当您有一个输入参数时,即函数观察到但不修改的内容,请考虑通过const引用const &)传递它,以避免无用的深拷贝(可能需要动态内存分配等)。

void addFile(const std::string& filename, 
             const std::set<std::string>& filePaths)

顺便说一句:
当然,如果你要传递的参数是易于复制,例如 int 类型,那么可以直接按值传递参数 :)


非常感谢您的回复。我理解您的意思,但是当我需要使用值或引用时,仍然让我感到困惑。在这里,我将要在映射中存储值,所以传递值是好的选择?还是传递引用? - sam_k
@Sam_k:请将两个方面区分开来:您在地图(或其他容器)中存储的内容和作为参数传递给函数的内容。我的答案侧重于传递什么作为参数,我不会在此评论中重复我的答案。相反,关于将东西存储在容器中,通常存储值是一个好选择:它对值进行深层复制,因此它们“物理”包含在容器中,并与其他外部上下文解耦(这也简化了所有权、生命周期管理等)。 - Mr.C64

0
如果您的容器集合非常大,而传递给函数的字符串相对较小,我可以采用以下方式:
void addFile(const string filename, const set< std::string> & filePaths)

1
“insert” 返回一个 pair<iterator, bool>,其中第二个元素为 true 表示插入成功,false 表示失败,这似乎是他想要检查的。你认为这有什么问题吗? - IllusiveBrian
没错。我正在检查插入函数返回的真或假。 - sam_k

0
第一个具有“更好”的性能,因为第二个在传递之前复制了字符串。由于您没有修改字符串,因此将实际字符串的引用传递给调用函数而不是制作副本没有任何缺点,并且复制引用比复制字符串占用更少的内存。话虽如此,如果您从未取消const限定符的string变量,编译器可能最终会将它们等效处理。这种差异在大参数上更有用,例如,如果您的filepaths变量有几千个元素,则通过引用传递而不是值传递可能会有非常明显的差异。
相关:在C++中按值传递还是按常量引用传递更好?

0
首先,你应该永远不要通过const传递参数,因为几乎没有理由这样做。通过值传递已经确保你不能在调用站点更改变量,因为它被复制了。

现在,问题仍然存在于通过值或引用传递参数。答案比预期的要复杂得多。关于这个问题在 Stack Overflow 上有很多好的答案。

简而言之,当将可能大的对象(如std::vectorstd::string)传递给函数时,请使用以下成语化指南:

  • 当传递用于观察(只读)的对象时,请传递到const的引用。
  • 当传递你想保留一个副本的参数时(所谓的sink argument),也请传递到const的引用。如果传递的对象是可移动的,则可以添加一种通过rvalue referenceT&&)获取参数的重载以进行优化。

相关信息:


2
除了内置类型,几乎没有理由这样做。内置类型有什么例外? - Neil Kirk
@NeilKirk 嗯,在我看来,有时候使用例如 const int 对于一个你不想在函数内修改的数字是很实用的(它只为实现者增加了价值)。尽管我的论点有点薄弱,但我还是删除了那部分。 - Felix Glas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接