我听取了香草萨特最近的谈话谁建议的理由来传递std::vector
和std::string
利用const &
在很大程度上消失了.他建议现在更好地编写如下函数:
std::string do_something ( std::string inval )
{
std::string return_val;
// ... do stuff ...
return return_val;
}
Run Code Online (Sandbox Code Playgroud)
我理解return_val
在函数返回时将是一个rvalue,因此可以使用非常便宜的移动语义返回.但是,inval
仍然远大于引用的大小(通常实现为指针).这是因为a std::string
具有各种组件,包括指向堆的指针和char[]
用于短字符串优化的成员.所以在我看来,通过引用传递仍然是一个好主意.
谁能解释为什么Herb可能会说这个?
我是C++初学者,但不是编程初学者.我正在努力学习C++(c ++ 11),对我来说,最重要的是有点不清楚:传递参数.
我考虑过这些简单的例子:
一个包含其所有成员基本类型的类:
CreditCard(std::string number, int expMonth, int expYear,int pin):number(number), expMonth(expMonth), expYear(expYear), pin(pin)
具有成员基本类型+ 1复杂类型的类:
Account(std::string number, float amount, CreditCard creditCard) : number(number), amount(amount), creditCard(creditCard)
具有成员基本类型的类+具有某种复杂类型的1个集合:
Client(std::string firstName, std::string lastName, std::vector<Account> accounts):firstName(firstName), lastName(lastName), accounts(accounts)
当我创建一个帐户时,我这样做:
CreditCard cc("12345",2,2015,1001);
Account acc("asdasd",345, cc);
Run Code Online (Sandbox Code Playgroud)
显然,在这种情况下,信用卡将被复制两次.如果我重写该构造函数为
Account(std::string number, float amount, CreditCard& creditCard)
: number(number)
, amount(amount)
, creditCard(creditCard)
Run Code Online (Sandbox Code Playgroud)
会有一份副本.如果我把它重写为
Account(std::string number, float amount, CreditCard&& creditCard)
: number(number)
, amount(amount)
, creditCard(std::forward<CreditCard>(creditCard))
Run Code Online (Sandbox Code Playgroud)
将有2个动作,没有副本.
我想有时您可能想要复制一些参数,有时您不希望在创建该对象时进行复制.
我来自C#,用于引用,对我来说有点奇怪,我认为每个参数应该有2个重载,但我知道我错了.
有没有关于如何在C++中发送参数的最佳实践,因为我真的发现它,比方说,并非琐碎.你会如何处理我上面提到的例子?
我有一个简单的课程:
class X
{
std::string S;
X (const std::string& s) : S(s) { }
};
Run Code Online (Sandbox Code Playgroud)
我最近读过一些关于rvalues的内容,我一直在想,如果我应该编写X
使用rvalue的构造函数,那么我能够检测出std::string
类型的临时对象吗?
我认为应该看起来像:
X (std::string&& s) : S(s) { }
Run Code Online (Sandbox Code Playgroud)
据我所知,在支持C++ 11的编译器中实现std :: string应该在可用时使用它的移动构造函数.
我有这样的模板:
template<typename T>
struct foo {
T m_t;
foo(T t) : m_t(t) {}
};
Run Code Online (Sandbox Code Playgroud)
问题是我想支持小/常规类型和巨大类型(如矩阵)T
.您是否建议我像这样编写构造函数初始化列表
foo (T t) : m_t(std::move(t)) {}
Run Code Online (Sandbox Code Playgroud)
并要求类型T
始终支持移动构造,即使是较小的类型?还有更好的方法吗?
最近我看到了几个这样的代码示例,其中std :: move用于构造函数初始化列表(不是移动构造函数).
class A {
public:
A(std::shared_ptr<Res> res) : myRes(std::move(res)) {
// ...
}
private:
std::shared_ptr<Res> myRes;
}
Run Code Online (Sandbox Code Playgroud)
我得到的信息是这个结构是出于优化原因.我个人使用std :: move尽可能少见.我威胁他们作为演员(如Scott Meyers所说),并且只在调用者代码中(只有例外是移动构造函数).对我来说,它看起来像某种混淆或微观优化,但也许我错了.是不是真的,如果没有std :: move,编译器不会产生更快的代码?
假设我有一个类,我打算将它作为可实例化的类直接暴露给程序员:
class Base
{
public:
Base(std::string text) : m_text(std::move(text)) {}
private:
std::string m_text;
};
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.这里不需要rvalue构造函数.现在,在未来的某个时刻,我决定扩展Base:
class Derived : public Base
{
public:
Derived(const std::string &text) : Base(text) {}
};
Run Code Online (Sandbox Code Playgroud)
这让我感到困惑:我无法在Derived中按值获取字符串,因为这就是Base已经在做的事情 - 我最终会得到2个副本和1个移动.这里的const-reference构造函数还对rvalues执行不必要的复制.
问题是:如何复制+仅移动一次(就像Base中的简单构造函数一样)而不添加更多构造函数?