我有以下代码:
#include <vector>
#include <iostream>
std::vector <int> a;
int append(){
a.emplace_back(0);
return 10;
}
int main(){
a = {0};
a[0] = append();
std::cout << a[0] << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该函数append()的副作用是将向量大小增加一。由于向量的工作方式,当超出其容量时,可能会触发其内存的重新分配。
因此,在执行 时a[0] = append(),如果发生重新分配,则 thena[0]无效并指向向量的旧内存。因此,您可以预期向量最终会变为,{0, 0}而不是{10, 0},因为它分配给旧向量a[0]而不是新向量。
让我感到困惑的是,这种行为在 C++14 和 C++17 之间发生了变化。
在 C++14 上,程序将打印 0。在 C++17 上,它将打印 10,这意味着a[0]实际上分配了 10。所以,我有以下问题,但我找不到答案:
a[0]在评估赋值表达式的 RHS 之后评估 的内存地址?C++14 之前是否对此进行了评估,这就是它发生变化的原因?volatile int lhs = 1;
int rhs = 2;
int x = 3;
x = lhs = rhs;
Run Code Online (Sandbox Code Playgroud)
赋值运算符是否返回 (typeof lhs)rhs ?或者它是否返回新的,只是读取 lhs 的值?这对我来说很重要,因为 lhs 是不稳定的,并且它可以在分配之间发生变化。
我在 cppreference 找不到答案。
请查看下面的代码并告诉我它是否会在将来导致问题,如果是,那么如何避免它们.
class Note
{
int id;
std::string text;
public:
// ... some ctors here...
Note(const Note& other) : id(other.id), text(other.text) {}
void operator=(const Note& other) // returns void: no chaining wanted
{
if (&other == this) return;
text = other.text;
// NB: id stays the same!
}
...
};
Run Code Online (Sandbox Code Playgroud)
简而言之,我希望复制构造函数能够创建对象的精确副本,包括其(数据库)ID字段.另一方面,当我分配时,我只想复制数据字段.但我有一些担忧,因为通常复制ctor和operator =具有相同的语义.
id字段仅由Note及其朋友使用.对于所有其他客户端,赋值运算符确实创建了精确副本.用例:当我想编辑一个笔记时,我使用copy ctor创建一个副本,编辑它,然后在管理Notes的Notebook类上调用save:
Note n(notebook.getNote(id));
n = editNote(n); // pass by const ref (for the case edit is canceled)
notebook.saveNote(n);
Run Code Online (Sandbox Code Playgroud)
另一方面,当我想要创建一个与现有音符具有相同内容的全新音符时,我可以这样做:
Note n;
n = notebook.getNote(id);
n.setText("This is a copy"); …Run Code Online (Sandbox Code Playgroud) 我会倾向于
if (object == nil)
Run Code Online (Sandbox Code Playgroud)
但我在一些教程中注意到了使用
if (nil == object)
Run Code Online (Sandbox Code Playgroud)
这只是一种风格的东西,还是有一些合理的理由使用这两种格式?
coding-style objective-c assignment-operator comparison-operators
class B;
class A{
B *b;
public:
void operator= (B *b){
this->b = b;
}
};
B *b = new B()
A *a = new A();
a = b;
Run Code Online (Sandbox Code Playgroud)
我收到"无法转换B*为A*"错误.有没有解决的办法?
现在,如果有办法,如果我使用类似的东西:
a = NULL;
Run Code Online (Sandbox Code Playgroud)
将使用哪个运算符"="?
我环顾四周,一个地方说它是一个"赋值运算符",但它们也列出了=作为赋值运算符.那有什么意义呢?我是一个很棒的java程序员,所以我想尽可能多地学习这门语言.
我有一个继承自MSFT类的类,因此无法更改,我希望我的派生类对其复制构造函数和复制赋值运算符具有相同的行为.我遇到的麻烦是,在复制构造函数中,您可以在初始化列表中为基类调用构造函数,但在运算符中,这不是一个选项.如何在赋值运算符中正确地重新创建此行为?仅仅在运算符重载的主体中调用基类的构造函数就足够了吗?
附加说明:基类继承自CObject,它具有operator =(),复制构造函数作为私有和未实现的方法,所以不幸的是,对这些方法的任何调用都将导致编译错误.
我在下面提供了一个简化的代码方案:
类声明:
class Base
{
protected:
int baseInt;
public:
Base(int);
}
class Derived : public Base
{
public:
Derived(const Derived& other);
Derived& operator=(const Derived& rhs);
private:
int derivedInt;
}
Run Code Online (Sandbox Code Playgroud)
派生类成员函数:
// Copy Constructor
Derived(const Derived& other) : Base(5)
{
derivedInt = other.derivedInt;
}
// Copy Assignment Operator
Derived& operator=(const Derived& rhs)
{
if (&rhs != this)
{
derivedInt = other.derivedInt;
return *this;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:更新语法并添加CObject备注
c++ inheritance copy-constructor initializer-list assignment-operator
考虑以下2个程序prog1和prog2.如果我尝试使用指针更改const限定变量的值,我会收到警告(而不是错误),但程序仍会运行并显示新值.但是如果我尝试使用赋值语句更改第二个程序中的值,我得到错误(不是警告).iptr"initialization discards qualifiers from pointer target type|"iassignment of read-only variable 'i'|
以下是此前提产生的混淆:
1)为什么我们允许const在任何情况下更改只读限定变量的值?它是否会破坏使用const限定符的目的?如果我们尝试这样做,我们不应该得到错误吗?
2)即使由于一些奇怪的原因我们被允许改变常量值,为什么在const使用指针(允许,带警告)和使用赋值操作改变只读限定变量的值之间进行区分(这是不允许的,并给我们一个错误)?
//prog1
#include <stdio.h>
int main ()
{
const int i=8;
int *ptr=&i;
*ptr=9;
printf("%d",*ptr); //Prints new value nevertheless
}
Run Code Online (Sandbox Code Playgroud)
警告:初始化从指针目标类型中丢弃限定符
//prog2
#include <stdio.h>
int main()
{
const int i=8;
i=10;
printf("%d",i);
}
Run Code Online (Sandbox Code Playgroud)
错误:分配只读变量'i'|
编辑H2CO3
在这里,我const不止一次更改限定变量的值.我只得到一个警告,与中相同prog1
//prog3
#include <stdio.h>
int main ()
{ …Run Code Online (Sandbox Code Playgroud) 假设T是一个C++类,如果我这样做T a = b;,是复制构造函数还是赋值运算符?
我当前的实验显示复制构造函数被调用,但不明白为什么.
#include <iostream>
using namespace std;
class T {
public:
// Default constructor.
T() : x("Default constructor") { }
// Copy constructor.
T(const T&) : x("Copy constructor") { }
// Assignment operator.
T& operator=(const T&) { x = "Assignment operator"; }
string x;
};
int main() {
T a;
T b = a;
cout << "T b = a; " << b.x << "\n";
b = a;
cout << "b = a; …Run Code Online (Sandbox Code Playgroud) C++ 17标准通过一条规则来修改C++语言的操作顺序的定义,结果如下:
在每个简单赋值表达式E1 = E2和每个复合赋值表达式E1 @ = E2中,E2的每个值计算和副作用在E1的每个值计算和副作用之前被排序.
然而,在编译GCC 8.1下面的代码时,-std=c++17和-Wall
int v[] { 0,1,2,3,4,5,6,7 };
int *p0 = &v[0];
*p0++ = *p0 + 1;
cout << "v[0]: " << v[0] << endl;
Run Code Online (Sandbox Code Playgroud)
我收到以下警告:
main.cpp:266:8: warning: operation on 'p0' may be undefined [-Wsequence-point]
*p0++ = *p0 + 1;
~~^~
Run Code Online (Sandbox Code Playgroud)
输出是:
v[0]: 1
问题是:警告是错误的吗?
c++ ×6
c ×2
c++17 ×2
c++14 ×1
coding-style ×1
const ×1
constants ×1
inheritance ×1
java ×1
objective-c ×1
pointers ×1
semantics ×1
stdvector ×1
volatile ×1