我正在尝试确定C++函数是否安全返回具有构造函数和析构函数的对象.我对标准的理解是它应该是可能的,但我用简单的例子进行的测试表明它可能有问题.例如以下程序:
#include <iostream>
using namespace std;
struct My
{ My() { cout << "My constructor " << endl; }
~My() { cout << "My destructor " << endl; }
};
My function() { My my; cout << "My function" << endl; return my; }
int main()
{ My my = function();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
给出输出:
My constructor
My function
My destructor
My destructor
Run Code Online (Sandbox Code Playgroud)
在MSVC++上编译时,但使用gcc编译时会得到以下输出:
My constructor
My function
My destructor
Run Code Online (Sandbox Code Playgroud)
这是"未定义的行为"的情况,还是一个不按标准方式运行的编译器?如果是后者,哪个?gcc输出更接近我的预期.
到目前为止,我一直在设计我的类,假设每个构造函数调用最多只有一个析构函数调用,但是这个例子似乎表明这个假设并不总是成立,并且可能依赖于编译器.标准中是否有任何内容指定此处应该发生什么,或者最好避免函数返回非平凡对象?如果这个问题是重复的,请道歉.
我有以下代码片段.有谁知道为什么在主函数中没有为所有情况调用此移动构造函数?为什么要编译呢?赋值运算符是私有的吗?链接:http://ideone.com/bZPnyY
#include <iostream>
#include <vector>
class A{
public:
A(int i){
std::cout << "Constructor "<< i <<std::endl;
for(int l = 0; l<i;l++){
vec.push_back(l);
}
};
A(A && ref): vec(std::move(ref.vec))
{
std::cout << "Move constructor"<<std::endl;
}
A & operator=(A && ref){
if(this != &ref){
vec = std::move(ref.vec);
}
std::cout << "Move assignment"<<std::endl;
return *this;
}
std::vector<int> vec;
private:
A(const A & ref);
A(A & ref);
A & operator=(A & ref);
};
A makeA(){
A a(3);
return a;
}
int …Run Code Online (Sandbox Code Playgroud) 我有一个处理和存储大量数据的函数,然后它将结果作为类的向量返回.存储在此函数中的数据量非常大,我希望在完成其工作后清除该函数的存储内存.是否有必要这样做(功能是否自动清除内存)还是应该通过某些功能清除内存?
更新:
vector<customers> process(char* const *filename, vector<int> ID)
{
vector<customers> list_of_customers;
(perform some actions)
return list_of_customers;
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试理解C++ 11中的移动语义,并且我编写了一小段代码来检查在创建对象时调用哪些构造函数.
这是代码:
#include <iostream>
using namespace std;
class Bar
{
public:
int b;
Bar();
Bar(const Bar&);
~Bar();
};
class Foo
{
public:
int d;
Bar* b;
Foo();
Foo(const Foo&);
Foo(Foo&& other);
~Foo();
Foo& operator = (Foo);
};
Foo test();
Foo::Foo()
{
cout << "Default ctr of foo called\n";
b = new Bar();
}
Foo::~Foo()
{
delete b;
}
Foo::Foo(const Foo& other)
{
cout << "Copy ctr of foo called\n";
d = other.d;
b = new Bar();
b->b = other.b->b; …Run Code Online (Sandbox Code Playgroud) 在简要(也可能是过时的和过于简单化)总结返回值优化力学读起来就像这样:
一个实现可以在调用者的堆栈帧中创建一个隐藏的对象,并将这个对象的地址传递给函数。然后将函数的返回值复制到隐藏对象中 (...) 大约 1991 年,Walter Bright发明了一种最小化复制的技术,有效地将函数内部的隐藏对象和命名对象替换为用于保存结果的对象 [1 ]
由于这是一个在 SO 上被广泛讨论的话题,我只会链接我找到的最完整的QA。
我的问题是,为什么不总是应用返回值优化?更具体地说(基于 中的定义[1])为什么每次函数调用都不总是发生这种替换,因为函数返回类型(因此堆栈上的大小)在编译时总是已知的,这似乎是一个非常有用的功能。
以下来自我的C++书籍的引文:
当我们使用直接初始化时,我们要求编译器使用普通函数匹配来选择与我们提供的参数最匹配的构造函数.当我们使用复制初始化时,我们要求编译器将右侧操作数复制到正在创建的对象中,必要时转换该操作数.
对我来说,这个粗体位会产生一些模糊性.它使得听起来像右手操作数被转换为类类型,然后使用复制构造函数,例如;
string s = "hello";
Run Code Online (Sandbox Code Playgroud)
会成为...
string s = string("hello");
Run Code Online (Sandbox Code Playgroud)
它使用复制构造函数.如果这是真的那么我的测试程序;
#include <iostream>
using namespace std;
class A{
public:
A(const A& b): data(b.data) { cout << "The first way" << endl;}
A(const char* c): data(c) { cout << "The second way" << endl;}
string data;
};
int main(){
A first("hello");
A second = "sup";
}
Run Code Online (Sandbox Code Playgroud)
应该产生"第二种方式,第二种方式,第一种方式".然而它反而打印出"第二种方式,第二种方式".从这里我可以得出结论它是使用const char*构造函数而不是复制构造函数.我会好的,除非后来说......
在复制初始化期间,允许编译器(但没有义务)跳过复制/移动构造函数并直接创建对象.也就是说,允许编译器重写
Run Code Online (Sandbox Code Playgroud)string null_book = "9-999-99999-9";成
Run Code Online (Sandbox Code Playgroud)string null_book("9-999-99999-9");但是,即使编译器省略了对复制/移动构造函数的调用,复制/移动构造函数也必须存在,并且必须在程序中的该点可访问(例如,非私有).
我不确定为什么复制构造函数甚至需要在这些示例中提及,否则
string null_book = "9-999-99999-9"
Run Code Online (Sandbox Code Playgroud)
总是隐含地意味着仍然使用const char*构造函数?实际上,我不需要定义复制构造函数以使上述工作正常.但是,如果我将"const A&"构造函数设置为私有(其他公共),那么我的程序将无法运行.为什么必须为不涉及它的隐式转换定义复制构造函数?什么构造函数"string null_book …
c++ copy-constructor implicit-conversion copy-initialization copy-elision
是否允许C++编译器替换:
const auto myType = MyType(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)
有:
const MyType myType(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)
即,发出任务,或有什么可以防止这种情况?
注意:我问的原因是我更喜欢第一个版本.
我正在尝试学习 C++ 中的资源管理,在我的研究中我遇到了一个有趣的优化。基本上,当使用复制构造函数初始化堆栈上的对象时,该对象是一个右值对象(它是右值对象吗?),而不是调用构造函数然后调用移动构造函数,编译器只是调用原始对象的构造函数。
Object c(Object(1)); // This is the same as Object c(1);
Object c(Object(Object(Object(Object(Object(1)))))); // This is also the same as Object c(1);
Run Code Online (Sandbox Code Playgroud)
Expected flow:
1. Object(1) calls the constructor and creates a nameless Object that will be removed as soon as it's created.
2. c notices this is an rvalue, and calls the move constructor.
3. Destructor for Object(1) is called.
Run Code Online (Sandbox Code Playgroud)
Actual flow:
1. c(1) is called.
Run Code Online (Sandbox Code Playgroud)
这很聪明,但是..如何?这个技巧背后的机制是什么?即使 Object 的构造函数接受指针和许多参数,这也有效。
我是 Rust 新手,试图了解从函数返回对象时如何传递所有权。在以下基于引用的实现中,由于引用没有所有权,因此当“s”超出范围时,它会被删除并释放。
fn dangle() -> &String { // dangle returns a reference to a String
let s = String::from("hello"); // s is a new String
&s // we return a reference to the String, s
} // Here, s goes out of scope, and is dropped. Its memory goes away.
// Danger!
Run Code Online (Sandbox Code Playgroud)
这是通过不返回引用来解决的:
fn no_dangle() -> String {
let s = String::from("hello");
s
}
Run Code Online (Sandbox Code Playgroud)
现在我尝试用 C++ 实现来理解这一点,如下所示:
std::string no_dangle() {
std::string s("hello world");
return s;
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,在 C++ 中,当从函数返回“s”时,使用复制构造函数创建另一个副本,并且在函数内部创建的“s”被释放。这意味着,创建了两个实际上不是光学的对象记忆方面。 …
当我有一个函数时,让我们调用它foo()。在foo()我创建一个名为的对象obj1,它是ClassA. 另外,我将对象的引用复制到std::queue<ClassA&> qu.
我的问题是:返回obj1前对象是否已销毁foo()?
代码示例:
class ClassA {...};
std::queue<ClassA&> qu;
void foo()
{
ClassA obj1;
qu.push_back(obj1);
}
int main()
{
foo();
return 0;
}
Run Code Online (Sandbox Code Playgroud) c++ ×10
c++11 ×4
constructor ×2
copy-elision ×2
copy ×1
destructor ×1
function ×1
move ×1
rust ×1
vector ×1