C ++构造函数 - 通过引用传递仅适用于const。为什么?

时间:2023-01-02 17:57:59

So earlier on today, I was catching up with good old C++ and when I was compiling my code it was not working. Like a few programmers, I started hacking about, and eventually found that adding the keyboard const cured the problem. However, I don't like hacking about a lot and want to find out why the code was working fine after adding the const.

所以今天早些时候,我正在追赶好的旧C ++,当我编写代码时,它无法正常工作。像一些程序员一样,我开始讨厌,并最终发现添加键盘const解决了这个问题。但是,我不喜欢黑客攻击很多,并希望找到为什么代码在添加const后工作正常。

This was my code BEFORE adding the const to the constructor:

这是我的代码之前将const添加到构造函数:

#include <iostream>
#include <string>

using namespace std;

class Names {
private:
    string _name;
    string _surname;

public:
    Names(string &name, string &surname) : _name(name), _surname(surname) {}

    string getName() const {return _name;}
    string getSurname() const {return _surname;}
};

int main(){
    Names names("Mike", "Man");

    cout << names.getName() << endl;
    cout << names.getSurname() << endl;
}

I was getting these errors:

我收到了这些错误:

names.cc:19:27: error: no matching function for call to ‘Names::Names(const char [5], const char [4])’
  Names names("Mike", "Man");
                           ^
names.cc:19:27: note: candidates are:
names.cc:11:2: note: Names::Names(std::string&, std::string&)
  Names(string &name, string &surname) : _name(name), _surname(surname) {}
  ^
names.cc:11:2: note:   no known conversion for argument 1 from ‘const char [5]’ to ‘std::string& {aka std::basic_string<char>&}’
names.cc:5:7: note: Names::Names(const Names&)
 class Names {
       ^
names.cc:5:7: note:   candidate expects 1 argument, 2 provided
<builtin>: recipe for target 'names' failed
make: *** [names] Error 1

However, after adding the const keyword within the constructor Names(string const &name, string const &surname) : _name(name), _surname(surname) {} -- it seems to be working.

但是,在构造函数Names(string const&name,string const&surname):_name(name),_surname(surname){}中添加const关键字后,它似乎正在工作。

This is my working code:

这是我的工作代码:

#include <iostream>
#include <string>
using namespace std;

class Names {
private:
    string _name;
    string _surname;

public:
    Names(string const &name, string const &surname) : _name(name), _surname(surname) {}

    string getName() const {return _name;}
    string getSurname() const {return _surname;}

};

int main(){
    Names names("Mike", "Man");
    cout << names.getName() << endl;
    cout << names.getSurname() << endl;
}

Now, a few questions:

现在,几个问题:

  1. Why was the code not working without the const for pass by reference? Is it good practice to always pass by reference in your constructors, and if so does it mean we have to use the const keyword?
  2. 为什么没有const的代码不能通过引用传递?在构造函数中始终通过引用传递是一种好习惯,如果是这样,那么我们必须使用const关键字?

  3. So if I passed by value in the constructor say: Names(string name, string surname) : _name(name), _surname(surname) {} does this mean that _name and _surname are null or are they the values passed. I know in pass by value, a copy of the variable is being made and changes are being made to the copy. But when does the copy get destoryed or out of scope? It is a bit confusing.
  4. 因此,如果我在构造函数中传递值,则说:Names(字符串名称,字符串姓氏):_ name(名称),_姓氏(姓氏){}这是否意味着_name和_surname为null或者是传递的值。我知道在传递值时,正在制作变量的副本,并且正在对副本进行更改。但是什么时候副本会被破坏或超出范围?这有点令人困惑。

Thanks

3 个解决方案

#1


13  

A string literal has to be converted to a std::string, which would be a temporary, and you cannot pass a temporary by non-const reference.

必须将字符串文字转换为std :: string,这将是一个临时的,并且您不能通过非const引用传递临时字符串。

#2


2  

It's quite difficult to add something to @CoryKramer's explanation

在@CoryKramer的解释中加入一些东西是相当困难的

A string literal has to be converted to a std::string, which would be a temporary, and you cannot pass a temporary by non-const reference.

必须将字符串文字转换为std :: string,这将是一个临时的,并且您不能通过非const引用传递临时字符串。

that would not just rephrase it.

这不仅仅是改写它。

Anyway, here's some instrumented code you (@CodeMan) could play with

无论如何,这里有一些你(@CodeMan)可以使用的检测代码

#include <iostream>

std::ostream& logger = std::clog;

struct A {
    A() = delete;
    A(int ii) : i(ii) {logger << "A(int) ctor\n";}
    A(const A& a) : i(a.i) {logger << "A copy ctor\n";}
    A& operator= (const A& a) { i = a.i; logger << "A copy assigment\n"; return *this;};
    // nothing to steal here
    A(A&& a) : i(a.i) {logger << "A move ctor\n";}
    A& operator= (A&& a) {i = a.i; logger << "A move assigment\n"; return *this;};
    ~A() {logger << "A dtor\n";}

    int i;
};

void foobar(const A& a) {
    logger << "foobaring const A&\n";
}

void foobar(A& a) {
    logger << "foobaring A&\n";
}


int main(){
  int i(42);  
  A a(i);
  logger << "ctored a\n===================\n";  
  foobar(a);
  logger << "foobared a\n-------------------\n";  
  foobar(i);
  logger << "foobared " << i << "\n===================" << std::endl;
}

live at Coliru's.

住在Coliru's。

As you can see from the output

从输出中可以看出

[...]
===================
foobaring A&
foobared a
-------------------
A(int) ctor
foobaring const A&
A dtor
foobared 42
===================
[...]

in the 2nd foobar invocation there's implicitly a temporary A ctored from that int argument, and that temporary A instance is passed into a different, namely the const version of foobar, thus as a const A &.

在第二个foobar调用中隐含了一个从该int参数中获得的临时A,并且临时A实例被传递给另一个实例,即foobar的const版本,因此作为const A&。

And you can also also that, right after that 2nd foobar returned, that temporary A is dtored.

而你也可以在第二个foobar返回后,那个临时的A被摧毁了。

#3


0  

1- "Mike" and "Man" in your call to the constructor are temporaries and non-const references cannot bind to temporaries. Passing built-in types by value is more efficient and all other objects by const reference.

1-“Mike”和“Man”在你对构造函数的调用中是临时的,非const引用不能绑定到临时对象。按值传递内置类型更有效,所有其他对象通过const引用。

2- If you pass by value _name and _surname will have the passed values. The passed parameters copies are local to the function so they get destroyed when the constructor goes out of scope.

2-如果传递值_name,_surname将传递值。传递的参数副本对于函数是本地的,因此当构造函数超出范围时它们会被销毁。

#1


13  

A string literal has to be converted to a std::string, which would be a temporary, and you cannot pass a temporary by non-const reference.

必须将字符串文字转换为std :: string,这将是一个临时的,并且您不能通过非const引用传递临时字符串。

#2


2  

It's quite difficult to add something to @CoryKramer's explanation

在@CoryKramer的解释中加入一些东西是相当困难的

A string literal has to be converted to a std::string, which would be a temporary, and you cannot pass a temporary by non-const reference.

必须将字符串文字转换为std :: string,这将是一个临时的,并且您不能通过非const引用传递临时字符串。

that would not just rephrase it.

这不仅仅是改写它。

Anyway, here's some instrumented code you (@CodeMan) could play with

无论如何,这里有一些你(@CodeMan)可以使用的检测代码

#include <iostream>

std::ostream& logger = std::clog;

struct A {
    A() = delete;
    A(int ii) : i(ii) {logger << "A(int) ctor\n";}
    A(const A& a) : i(a.i) {logger << "A copy ctor\n";}
    A& operator= (const A& a) { i = a.i; logger << "A copy assigment\n"; return *this;};
    // nothing to steal here
    A(A&& a) : i(a.i) {logger << "A move ctor\n";}
    A& operator= (A&& a) {i = a.i; logger << "A move assigment\n"; return *this;};
    ~A() {logger << "A dtor\n";}

    int i;
};

void foobar(const A& a) {
    logger << "foobaring const A&\n";
}

void foobar(A& a) {
    logger << "foobaring A&\n";
}


int main(){
  int i(42);  
  A a(i);
  logger << "ctored a\n===================\n";  
  foobar(a);
  logger << "foobared a\n-------------------\n";  
  foobar(i);
  logger << "foobared " << i << "\n===================" << std::endl;
}

live at Coliru's.

住在Coliru's。

As you can see from the output

从输出中可以看出

[...]
===================
foobaring A&
foobared a
-------------------
A(int) ctor
foobaring const A&
A dtor
foobared 42
===================
[...]

in the 2nd foobar invocation there's implicitly a temporary A ctored from that int argument, and that temporary A instance is passed into a different, namely the const version of foobar, thus as a const A &.

在第二个foobar调用中隐含了一个从该int参数中获得的临时A,并且临时A实例被传递给另一个实例,即foobar的const版本,因此作为const A&。

And you can also also that, right after that 2nd foobar returned, that temporary A is dtored.

而你也可以在第二个foobar返回后,那个临时的A被摧毁了。

#3


0  

1- "Mike" and "Man" in your call to the constructor are temporaries and non-const references cannot bind to temporaries. Passing built-in types by value is more efficient and all other objects by const reference.

1-“Mike”和“Man”在你对构造函数的调用中是临时的,非const引用不能绑定到临时对象。按值传递内置类型更有效,所有其他对象通过const引用。

2- If you pass by value _name and _surname will have the passed values. The passed parameters copies are local to the function so they get destroyed when the constructor goes out of scope.

2-如果传递值_name,_surname将传递值。传递的参数副本对于函数是本地的,因此当构造函数超出范围时它们会被销毁。